三分钟带你了解ES【详解版】-程序员宅基地

技术标签: elasticsearch  lucene  搜索引擎  

1 ES是什么

Elasticsearch 是一个分布式的 RESTful 搜索和分析引擎,可用来集中存储您的数据,以便您对形形色色、规模不一的数据进行搜索、索引和分析。

上面是​​官网-API文档​​对的定位描述。ES 是一个分布式的搜索引擎,数据存储形式与我们常用的 MySQL 的存储形式 — rows 不同,ES 会将数据以 JSON 结构存储到一个文档。一个文档写入 ES 后,我们可以在 1 秒左右查询到它,因此我们称 ES 在分布式中数据查询是准实时的。

提问:那么这种将一行行数据变成

我们传统的关系型数据库一般的存储形式是数据结构不固定,长度不固定。这时如果用关系型数据库做存储,那么我们表设计上,只能用一个

为了可以适应高并发,又能快速检索、分析数据的搜索分析引擎,像倒排索引实现可以通过词条快速查找文档的,而倒排索引的实现与这种文档存储数据的方式密不可分。

ES 的适用场景所具有的特点:

  • 海量数据的搜索服务
  • 对实时性要求较高
  • 对事务要求不高

2 倒排索引

倒排索引是文档检索系统中最常用的数据结构。

说到帮助搜索引擎检索数据的数据结构,我们最熟悉的应该就是倒排索引了。过去很多人喜欢用字典来举例,因为它的原理和我们使用中文字典查找汉字是相似的。

ES 会在我们保存一份文档的时候,将文档根据指定分词器进行分词,然后维护关键词和文档的关系——倒排索引。后面我们通过一些词条进行检索的时候,就可以通过这个索引找到对应相关的文档。

2.1 例子

下面举个例子。

插入两份文档,内容如下:

  1. we like java java java
  2. we like lucene lucene lucene

建立倒排索引大体流程如下:

  1. 首先对所有数据的内容进行拆分,拆分成唯一的一个个词语(词条)
  2. 然后建立词条和对应文档的对应关系,具体如下:

词条

(文档ID,频率)

词条在文档中的位置

we

(1,1) (2,1)

(0) (0)

like

(1,1) (2,1)

(1) (1)

java

(1,3)

(2,3,4)

lucene

(2,3)

(2,3,4)

注意:这里用表格来展示是为了方便理解,但是倒排索引其实是树结构。

那这时我检索词条:

3 使用ES必须知道的基本概念

这里的概念是我们在使用过程中绝对无法绕开的概念,所以我们需要知道,否则无法和同事交流,哪怕仅仅是使用级别。

3.1 document(文档)

在 ES 中,一份文档相当于 MySQL 中的一行记录,数据以 JSON 格式保存。文档被更新时,版本号会被增加。

3.2 Index(索引)

存储文档的地方,类似 MySQL 中的表。

3.3 Mapping(映射)

映射是定义一个文件和它所包含的字段如何被存储和索引的过程(​​这是官方定义​​)。

文档里面有许多字段,这些字段有自己的类型,采用什么分词器等等,我们可以通过。

3.4 type(类型)

这是比较老旧版本会用到的定义,在 ES5 的时代,它可以对 Index 做更精细地划分,那个时代的 Index 更像 MySQL 的实例,而 type 类似 MySQL 的 table。

ES 5.x 中一个index可以有多种type。

ES 6.x 中一个index只能有一种type。

ES 7.x 以后,将逐步移除type这个概念,现在的操作已经不再使用,默认_doc。

4 了解常用的DSL

在 MySQL 中,我们经常使用 SQL 通过客户端操作 MySQL,而 DSL 正是我们通过客户端发送给 ES 的操作指令。

下面只写一些现在我们常常接触的简单的 DSL,更多的请看 官网。

4.1 Index

官网API:​​https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html​

4.1.1 创建索引

可以先建索引,再设置 mapping,也可以直接一次完成。

一次建好

复制
PUT goods{
 "mappings": {
 "properties": {
 "brand": {
 "type": "keyword"
 },
 "category": {
 "type": "keyword"
 },
 "num": {
 "type": "integer"
 },
 "price": {
 "type": "double"
 },
 "title": {
 "type": "text",
 "analyzer": "ik_smart"
 },
 "id": {
 "type": "long"
 }
 }
 }
}

4.1.2 查询 index 信息

GET index_name

4.1.3 删除 index

DELETE index_name

4.1.4 关闭 index

POST index_name/_close

当索引进入关闭状态,是不能操作文档的。

4.1.5 打开 index

POST index_name/_open

4.1.6 Aliases(别名) & Reindex

实际工作中,有很多情况可能都会需要重建 index,同时将旧的数据迁移到新 index 上,并且期望这个过程可以零停机,那么这时我们就可以用到 aliases 和 reindex 了。

事实上,我们程序访问 index,很少是访问真正的 indexName,一般我们会对 index 建别名,程序访问的是别名。因为如果使用别名,那么此别名背后的索引需要进行更换的时候对程序可以做到无感知。

下面是一个需要添加分词器而导致需要重建 index 和数据迁移的场景(这里只是举个简单场景,方便感受这些命令如何使用而已)。

1)先建立了一个 person,具体如下:

复制
PUT person
{
 "mappings" : {
 "properties" : {
 "address" : {
 "type" : "text"
 },
 "age" : {
 "type" : "integer"
 },
 "name" : {
 "type" : "keyword"
 }
 }
 }
}

2)后端程序访问是用别名

复制
POST _aliases
{
 "actions": [
 {
 "add": {
 "index": "person",
 "alias": "person_index"
 }
 }
 ]
}

3)添加了一些数据

复制
PUT person/_doc/1
{
 "name": "test1",
 "age": 18,
 "address": "test address"
}

4)添加分词器,更改 mapping 设置

复制
PUT person2
{
 "mappings" : {
 "properties" : {
 "address" : {
 "type" : "text",
 "analyzer": "ik_smart"
 },
 "age" : {
 "type" : "integer"
 },
 "name" : {
 "type" : "keyword"
 }
 }
 }
}

5)别名操作(支持多个操作,并具有原子性)

复制
POST /_aliases
{
 "actions" : [
 # 添加别名
 { "add" : { "index" : "person2", "alias" : "person_index" } }
 ]
}

这时我们后端程序只能对 person_index 进行读操作,无法进行写操作。

6)将 person 中的数据导入到 person2 中(如果是不同进程,支持远程访问)

复制
POST _reindex
{
 "source": {
 "index": "person"
 },
 "dest": {
 "index": "person2"
 }
}

7)去掉 person

复制
POST /_aliases
{
 "actions" : [
 # 将 person 从别名 person_index 中移除
 { "remove" : { "index" : "person", "alias" : "person_index" } }
 ]
}

这时后端程序对 person_index 的读写操作均恢复正常。

更多信息可以查阅官网:​​reindex​​​ ​​aliases​

4.2 设置 Mapping

添加 index。

复制
PUT person
{
 "settings": {
 "number_of_shards": 1,
 "number_of_replicas": 1
 }
}

已经建好索引 person,但是没有设置 mapping,现在设置。

复制
PUT person/_mapping
{
 "properties": {
 "name": {
 "type": "keyword"
 },
 "age": {
 "type": "integer"
 },
 "address":{
 "type": "text",
 "analyzer": "ik_max_word"
 }
 }
}

index 确定后,不能修改已有字段,只能添加,以下增加一个 test字段作为例子。

复制
PUT person/_mapping
{
 "properties": {
 "test": {
 "type": "text"
 }
 }
}

查询 mapping 信息

复制
GET person/_mapping

4.3 使用频率较高的查询

这里只写一些比较常接触的语句,不过像 wildcard 这种,也有很多公司是禁止使用的,所以用的时候一定要了解公司规范要求。

先设置一个商品 index,具体如下:

复制
PUT goods
{
 "mappings": {
 "properties": {
 "brand": {
 "type": "keyword"
 },
 "category": {
 "type": "keyword"
 },
 "num": {
 "type": "integer"
 },
 "price": {
 "type": "double"
 },
 "title": {
 "type": "text",
 "analyzer": "ik_smart"
 },
 "id": {
 "type": "long"
 }
 }
 }
}

字段说明:

  1. title:商品标题
  2. price:商品价格
  3. num:商品库存
  4. category:商品类别
  5. brand:品牌名称

4.3.1 分页与排序

复制
# GET 索引库名称/_search,默认展示10条数据
GET goods/_doc/_search
{
 "query": {
 "match_all": {}
 },
 "sort": [
 {
 "price": {
 "order": "desc" # 根据价格降序排序
 }
 }
 ],
 "from": 0, # 从哪一条开始
 "size": 20 # 显示多少条 
}

4.3.1.1 深度翻页

ES 深度分页存在的问题:

  1. 性能问题
  1. 深度分页会导致搜索引擎遍历大量的数据,因此会对性能产生负面影响。尤其是在数据量庞大的情况下,可能会导致搜索请求变得非常慢。
  1. 排序问题
  1. 这是由于不同分片上的数据排序不一致所导致的(每个分片需要将自己的处理结果给到协调节点,再由协调节点来计算出最后的结果)。
  1. 索引更新问题
  1. 如果在进行深度分页时,索引被更新了,那么可能会导致部分数据被遗漏或重复显示(为了避免这个问题,可以使用游标或滚动搜索等机制来遍历数据)。
  1. 内存问题
  1. 在进行深度分页时,Elasticsearch 需要将所有的搜索结果都存储在内存中。如果结果集非常大,那么会占用大量的内存,甚至可能导致内存溢出(为了避免这个问题,可以使用游标或滚动搜索等机制来逐步处理数据)。

在 Elasticsearch 7.0 之前,我们是采用 scroll 来解决深度分页的,但是到了 Elasticsearch 7.0 就开始不再推荐采用 scroll 了,推荐采用 search_after。

4.3.1.1.1 scroll

详细请看​​官方文档​

以下例子来自于官网

1)先查询并生成快照

scroll=1m 是保留1分钟快照的意思,即是符合当前查询条件的数据的结果集合保留快照1分钟

复制
POST /index_name/_search?scroll=1m
{
 "size": 100,
 "query": {
 "match": {
 "message": "foo"
 }
 }
}

假设返回的 scroll_id 是 DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==

2)那么,我们就可以使用这个 ID 进行滚动翻页了

复制
POST /_search/scroll 
{
 "scroll" : "1m", # 快照保持1分钟,重新计时 
 "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==" 
}

3)查询完后,记得删除游标

复制
DELETE /_search/scroll
{
 "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ=="
}

这里详细说下游标的工作方式:

当第一次发起 scroll 请求时,ES 会创建一个包含搜索结果的快照,并返回一个唯一的滚动 ID。在接下来的每个 scroll 请求中,都需要带上这个滚动 ID,表示要获取与该搜索上下文匹配的下一批结果。因为每个 scroll 请求都使用了相同的搜索上下文,所以每个请求返回的结果都是相同的,只是可能包含不同的文档。如果 scroll 请求返回的结果集合大小不足以填满请求的大小限制,则 ES 会在后台继续搜索,并将结果添加到当前结果集中,直到结果集合大小达到请求的大小限制或搜索完成为止。

由于 scroll 机制的实现方式,每次请求返回的结果可以是任意大小,可以避免一次性读取所有结果可能导致的内存问题。同时,由于滚动 ID 只在指定的时间段内有效,所以可以在不消耗过多内存的情况下,分批次处理大量数据。但是,需要注意的是,如果时间段设置得过短,可能会导致滚动 ID 过期,需要重新发起搜索请求。

4.3.1.1.2 search_after

详细请看​​官网​

以下例子来自于官网

1)先查询

复制
GET twitter/_search
{
 "query": {
 "match": {
 "title": "elasticsearch"
 }
 },
 "sort": [
 {"date": "asc"},
 {"tie_breaker_id": "asc"} 
 ]
}

假设响应如下:

复制
{
 "took" : 17,
 "timed_out" : false,
 "_shards" : ...,
 "hits" : {
 "total" : ...,
 "max_score" : null,
 "hits" : [
 ...
 {
 "_index" : "twitter",
 "_id" : "654322",
 "_score" : null,
 "_source" : ...,
 "sort" : [
 1463538855,
 "654322"
 ]
 },
 {
 "_index" : "twitter",
 "_id" : "654323",
 "_score" : null,
 "_source" : ...,
 "sort" : [ 
 1463538857,
 "654323"
 ]
 }
 ]
 }
}

2)接着,使用上面响应结果中最后一个文档的排序键

作为参数传递到下一次查询中(这里其实就是对应了查询示例中的两个排序字段 date 和 tie_breaker_id)

复制
GET twitter/_search
{
 "query": {
 "match": {
 "title": "elasticsearch"
 }
 },
 "search_after": [1463538857, "654323"],
 "sort": [
 {"date": "asc"},
 {"tie_breaker_id": "asc"}
 ]
}

这里有一个问题,如果我在第2页准备翻到第3页时,refresh 了可能会打乱排序,那么这个分页的结果就不对了。为了避免这种情况,我们可以使用 PIT 来保存当前搜索的索引状态。

具体使用如下:

1)先得到 PIT ID

复制
POST /index_name/_pit?keep_alive=1m

响应如下:

复制
{
 "id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA=="
}

2)使用 PIT ID 搜索

复制
GET /_search
{
 "size": 10000,
 "query": {
 "match" : {
 "user.id" : "elkbee"
 }
 },
 "pit": {
 "id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==", 
 "keep_alive": "1m"
 },
 "sort": [ 
 {"@timestamp": {"order": "asc", "format": "strict_date_optional_time_nanos", "numeric_type" : "date_nanos" }}
 ]
}

响应如下:

复制
{
 "pit_id" : "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==", 
 "took" : 17,
 "timed_out" : false,
 "_shards" : ...,
 "hits" : {
 "total" : ...,
 "max_score" : null,
 "hits" : [
 ...
 {
 "_index" : "my-index-000001",
 "_id" : "FaslK3QBySSL_rrj9zM5",
 "_score" : null,
 "_source" : ...,
 "sort" : [ 
 "2021-05-20T05:30:04.832Z",
 4294967298 
 ]
 }
 ]
 }
}

3)pit id + 排序键 翻页

复制
GET /_search
{
 "size": 10000,
 "query": {
 "match" : {
 "user.id" : "elkbee"
 }
 },
 "pit": {
 "id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==", 
 "keep_alive": "1m"
 },
 "sort": [
 {"@timestamp": {"order": "asc", "format": "strict_date_optional_time_nanos"}}
 ],
 "search_after": [ 
 "2021-05-20T05:30:04.832Z",
 4294967298
 ],
 "track_total_hits": false 
}

4)查询完后,删除 PIT

复制
DELETE /_pit
{
 "id" : "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA=="
}

scroll 和 search after 都是用来处理大数据时避免深度翻页的,它们区别如下:

  1. 实现方式不同
  1. scroll 使用游标来保持搜索上下文,而 search after 使用排序键来跟踪搜索进度。
  1. 参数设置不同
  1. scroll 需要指定一个时间段来保持搜索上下文,而 search after 需要指定一个排序字段和一个起始排序键来开始搜索。
  1. 数据处理方式不同
  1. scroll 适用于一次性处理所有数据的场景,每次请求返回的结果可以是任意大小,直到搜索上下文过期或搜索完成为止。而。
  1. 排序方式不同
  1. scroll 可能会导致排序不稳定的问题,而 search after 使用排序键来跟踪搜索进度,可以避免这个问题。
  1. 兼容性不同
  1. scroll 是 Elasticsearch 5.x 及之前版本的遗留功能,而 search after 是 Elasticsearch 7.0 中引入的新特性,Elasticsearch 7.0 开始推荐使用 search after。

4.3.2 match

想对搜索关键字进行分词,搜索的结果更全面。

特点

  1. 会对查询条件进行分词
  2. 然后将分词后的查询条件和词条进行等值匹配
  3. 默认取并集
复制
GET goods/_search
{
  "query": {
    "match": {
      "title": "华为手机"
    }
  }
}

# 指定取交集
GET goods/_search
{
  "query": {
    "match": {
      "title": {
        "query": "华为手机",
        "operator": "and"
      }
    }
  }
}

4.3.3 term

不想对搜索关键字进行分词,搜索的结果更加精确。

复制
GET goods/_search
{
 "query": {
 "term": {
 "title": {
 "value": "华为"
 }
 }
 }
}

4.3.4 range

当想对数值类型的字段做区间的搜索,例如商品价格。

复制
# 价格大于等于2000,小于等于3000
# gte: >= lte:<= gt:> lt:<
GET goods/_search
{
 "query": {
 "range": {
 "price": {
 "gte": 2000,
 "lte": 3000
 }
 }
 }
}

4.3.5 wildcard

当使用match搜索仍然查询不到数据,可以尝试使用模糊查询,范围更广。

复制
GET goods/_search
{
 "query": {
 "match": {
 "title": "华"
 }
 }
}

运行结果:

可以发现查询的结果中,那些title包含“华为”的数据查不出来,因为那些数据,没有分出"华"这一个字,而分出的就是"华为",这个时候我们若想把包含"华为"的数据都查出来,就可以使用模糊查询。

4.3.6 query_string

当不知道搜索的内容存储在哪个字段时,可以使用字符串搜索。

特点

  1. 会对查询条件进行分词
  2. 将分词后的查询条件和词条进行等值匹配
  3. 默认取并集(OR)
  4. 可以指定多个查询字段

1)不指定字段

复制
GET goods/_search
{
  "query": {
    "query_string": {
      "query": "华为手机"
    }
  }
}

2)指定字段

复制
GET goods/_search
{
  "query": {
    "query_string": {
      "fields": ["title", "brand"],
      "query": "华为手机"
    }
  }
}

运行结果:

4.3.7 bool

当存在多个查询条件时

语法

must(and):条件必须成立
must_not(not):条件必须不成立,必须和must或filter连接起来使用
should(or):条件可以成立
filter:条件必须成立,性能比must高(不会计算得分)

复制
# 查询品牌为华为,并且title包含手机的数据
GET goods/_search
{
 "query": {
 "bool": {
 "must": [
 {
 "term": {
 "brand": {
 "value": "华为"
 }
 }
 },
 {
 "match": {
 "title": "手机"
 }
 }
 ]
 }
 }
}

运行结果:

4.3.8 Aggregations

聚合查询

聚合类型:

  1. 指标聚合:相当于MySQL的聚合函数。比如max、min、avg、sum等。
  2. 桶聚合:相当于MySQL的 group by 操作。(不要对text类型的数据进行分组,会失败)

4.3.8.1 指标聚合

复制
# 指标聚合:找品牌是华为的商品中价格最高的商品价格
GET goods/_search
{
 "query": {
 "term": {
 "brand": {
 "value": "华为"
 }
 }
 },
 "aggs": {
 "max_price": {
 "max": {
 "field": "price"
 }
 }
 },
 "size": 0
}

运行结果:

4.3.8.2 桶聚合

复制
# 桶聚合:根据品牌聚合,看每个品牌的手机商品数据量
GET goods/_search
{
 "query": {
 "match": {
 "title": "手机"
 }
 }, 
 "aggs": {
 "brand_num": {
 "terms": {
 "field": "brand"
 }
 }
 },
 "size": 0
}

运行结果:

4.3.9 highlight(高亮查询)

复制
# 高亮: 让 title 中的“华为”和“手机”高亮起来
GET goods/_search
{
 "query": {
 "match": {
 "title": "华为手机"
 }
 },
 "highlight": {
 "fields": {
 # 高亮字段
 "title": {
 # 前缀
 "pre_tags": "<font class = 'color_class'>",
 # 后缀
 "post_tags": "</font>"
 }
 }
 }
}

运行结果:

5 总结

这篇文章的宗旨是希望可以帮助刚接触ES 的人可以快速了解ES,和掌握ES 的一些常用查询。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xxxzzzqqq_/article/details/130282382

智能推荐

leetcode 172. 阶乘后的零-程序员宅基地

文章浏览阅读63次。题目给定一个整数 n,返回 n! 结果尾数中零的数量。解题思路每个0都是由2 * 5得来的,相当于要求n!分解成质因子后2 * 5的数目,由于n中2的数目肯定是要大于5的数目,所以我们只需要求出n!中5的数目。C++代码class Solution {public: int trailingZeroes(int n) { ...

Day15-【Java SE进阶】IO流(一):File、IO流概述、File文件对象的创建、字节输入输出流FileInputStream FileoutputStream、释放资源。_outputstream释放-程序员宅基地

文章浏览阅读992次,点赞27次,收藏15次。UTF-8是Unicode字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节。文件字节输入流:每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1。注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码。定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。UTF-8字符集:汉字占3个字节,英文、数字占1个字节。GBK字符集:汉字占2个字节,英文、数字占1个字节。GBK规定:汉字的第一个字节的第一位必须是1。_outputstream释放

jeecgboot重新登录_jeecg 登录自动退出-程序员宅基地

文章浏览阅读1.8k次,点赞3次,收藏3次。解决jeecgboot每次登录进去都会弹出请重新登录问题,在utils文件下找到request.js文件注释这段代码即可_jeecg 登录自动退出

数据中心供配电系统负荷计算实例分析-程序员宅基地

文章浏览阅读3.4k次。我国目前普遍采用需要系数法和二项式系数法确定用电设备的负荷,其中需要系数法是国际上普遍采用的确定计算负荷的方法,最为简便;而二项式系数法在确定设备台数较少且各台设备容量差..._数据中心用电负荷统计变压器

HTML5期末大作业:网页制作代码 网站设计——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 dreamweaver作业静态HTML网页设计模板_网页设计成品百度网盘-程序员宅基地

文章浏览阅读7k次,点赞4次,收藏46次。HTML5期末大作业:网页制作代码 网站设计——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 dreamweaver作业静态HTML网页设计模板常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 军事、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他 等网页设计题目, A+水平作业_网页设计成品百度网盘

【Jailhouse 文章】Look Mum, no VM Exits_jailhouse sr-iov-程序员宅基地

文章浏览阅读392次。jailhouse 文章翻译,Look Mum, no VM Exits!_jailhouse sr-iov

随便推点

chatgpt赋能python:Python怎么删除文件中的某一行_python 删除文件特定几行-程序员宅基地

文章浏览阅读751次。本文由chatgpt生成,文章没有在chatgpt生成的基础上进行任何的修改。以上只是chatgpt能力的冰山一角。作为通用的Aigc大模型,只是展现它原本的实力。对于颠覆工作方式的ChatGPT,应该选择拥抱而不是抗拒,未来属于“会用”AI的人。AI职场汇报智能办公文案写作效率提升教程 专注于AI+职场+办公方向。下图是课程的整体大纲下图是AI职场汇报智能办公文案写作效率提升教程中用到的ai工具。_python 删除文件特定几行

Java过滤特殊字符的正则表达式_java正则表达式过滤特殊字符-程序员宅基地

文章浏览阅读2.1k次。【代码】Java过滤特殊字符的正则表达式。_java正则表达式过滤特殊字符

CSS中设置背景的7个属性及简写background注意点_background设置背景图片-程序员宅基地

文章浏览阅读5.7k次,点赞4次,收藏17次。css中背景的设置至关重要,也是一个难点,因为属性众多,对应的属性值也比较多,这里详细的列举了背景相关的7个属性及对应的属性值,并附上演示代码,后期要用的话,可以随时查看,那我们坐稳开车了······1: background-color 设置背景颜色2:background-image来设置背景图片- 语法:background-image:url(相对路径);-可以同时为一个元素指定背景颜色和背景图片,这样背景颜色将会作为背景图片的底色,一般情况下设置背景..._background设置背景图片

Win10 安装系统跳过创建用户,直接启用 Administrator_windows10msoobe进程-程序员宅基地

文章浏览阅读2.6k次,点赞2次,收藏8次。Win10 安装系统跳过创建用户,直接启用 Administrator_windows10msoobe进程

PyCharm2021安装教程-程序员宅基地

文章浏览阅读10w+次,点赞653次,收藏3k次。Windows安装pycharm教程新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入下载安装PyCharm1、进入官网PyCharm的下载地址:http://www.jetbrains.com/pycharm/downl_pycharm2021

《跨境电商——速卖通搜索排名规则解析与SEO技术》一一1.1 初识速卖通的搜索引擎...-程序员宅基地

文章浏览阅读835次。本节书摘来自异步社区出版社《跨境电商——速卖通搜索排名规则解析与SEO技术》一书中的第1章,第1.1节,作者: 冯晓宁,更多章节内容可以访问云栖社区“异步社区”公众号查看。1.1 初识速卖通的搜索引擎1.1.1 初识速卖通搜索作为速卖通卖家都应该知道,速卖通经常被视为“国际版的淘宝”。那么请想一下,普通消费者在淘宝网上购买商品的时候,他的行为应该..._跨境电商 速卖通搜索排名规则解析与seo技术 pdf

推荐文章

热门文章

相关标签