Elasticsearch入门

Elasticsearch 里存储文档数据和关系型数据库 MySQL 存储数据的概念的类比

类比图

倒排索引是什么?

“倒排索引”(inverted index)是一种数据结构,通常用于搜索引擎中。它可以将文档中的每个单词映射到包含该单词的所有文档的列表中,从而快速查找包含特定单词的文档。

对于 “es” 这个词,倒排索引会列出包含 “es” 的所有文档,其中每个文档都有一个相关性得分来表示该文档与查询的匹配程度。这个得分通常基于诸如单词频率、文档长度等因素计算得出,以便能够根据相关性对结果进行排序。

倒排索引通常是搜索引擎的核心部分,因为它使得搜索引擎可以在海量文档中快速地查找包含特定单词的文档,并且可以根据相关性得分对搜索结果进行排序。

我个人的理解是:正向索引是 文档 指向关键词的 映射
倒排索引是 关键词指向文档的 映射

索引的使用

HTTP-索引-创建

ES 服务器发 PUT 请求 : http://127.0.0.1:9200/shopping

HTTP-索引-查询 & 删除

查看所有索引

这里请求路径中的_cat 表示查看的意思, indices 表示索引,所以整体含义就是查看当前 ES服务器中的所有索引,就好像 MySQL 中的 show tables 的感觉
http://127.0.0.1:9200/cat/indices?v
cat的显示
表头 含义
health 当前服务器健康状态: green(集群完整) yellow(单点正常、集群不完整) red(单点不正常)
status 索引打开、关闭状态
index 索引名
uuid 索引统一编号
pri 主分片数量
rep 副本数量
docs.count 可用文档数量
docs.deleted 文档删除状态(逻辑删除)
store.size 主分片和副分片整体占空间大小
pri.store.size 主分片占空间大小

查看单个索引

向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"shopping": {//索引名
"aliases": {},//别名
"mappings": {},//映射
"settings": {//设置
"index": {//设置 - 索引
"creation_date": "1617861426847",//设置 - 索引 - 创建时间
"number_of_shards": "1",//设置 - 索引 - 主分片数量
"number_of_replicas": "1",//设置 - 索引 - 主分片数量
"uuid": "J0WlEhh4R7aDrfIc3AkwWQ",//设置 - 索引 - 主分片数量
"version": {//设置 - 索引 - 主分片数量
"created": "7080099"
},
"provided_name": "shopping"//设置 - 索引 - 主分片数量
}
}
}
}

删除索引

向 ES 服务器发 DELETE 请求 : http://127.0.0.1:9200/shopping

HTTP-文档-创建(Put & Post)

假设索引已经创建好了,接下来我们来创建文档,并添加数据。这里的文档可以类比为关系型数据库中的表数据,添加的数据格式为 JSON 格式

在 Postman 中,向 ES 服务器发 POST 请求 : http://127.0.0.1:9200/shopping/_doc ,请求体JSON内容为:

1
{ "title":"小米手机", "category":"小米", "images":"http://www.gulixueyuan.com/xm.jpg", "price":3999.00 }

返回结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"_index": "shopping",//索引
"_type": "_doc",//类型-文档
"_id": "ANQqsHgBaKNfVnMbhZYU",//唯一标识,可以类比为 MySQL 中的主键,随机生成
"_version": 1,//版本
"result": "created",//结果,这里的 create 表示创建成功
"_shards": {//
"total": 2,//分片 - 总数
"successful": 1,//分片 - 总数
"failed": 0//分片 - 总数
},
"_seq_no": 0,
"_primary_term": 1
}

上面的数据创建后,由于没有指定数据唯一性标识(ID),默认情况下, ES 服务器会随机生成一个。

如果想要自定义唯一性标识,需要在创建时指定: http://127.0.0.1:9200/shopping/_doc/1 请求体JSON内容,此处需要注意:如果增加数据时明确数据主键,那么请求方式也可以为 PUT。

HTTP-查询-主键查询 & 全查询

查看文档时,需要指明文档的唯一性标识,类似于 MySQL 中数据的主键查询

在 Postman 中,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping/_doc/1
查找不存在的内容,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping/_doc/1001。
查看索引下所有数据,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping/_search。

HTTP-全量修改 & 局部修改 & 删除

全量修改

和新增文档一样,输入相同的 URL 地址请求,如果请求体变化,会将原有的数据内容覆盖

在 Postman 中,向 ES 服务器发 POST 请求 : http://127.0.0.1:9200/shopping/_doc/1

请求体JSON内容为:

1
{ "title":"华为手机", "category":"华为", "images":"http://www.gulixueyuan.com/hw.jpg", "price":1999.00 }

更换请求体 就可以更换数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "updated",//<-----------updated 表示数据被更新
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}

局部修改

修改数据时,也可以只修改某一给条数据的局部信息

在 Postman 中,向 ES 服务器发 POST 请求 : http://127.0.0.1:9200/shopping/_update/1。

请求体JSON内容为:

1
{ "doc": { "title":"小米手机", "category":"小米" } }

删除

删除一个文档不会立即从磁盘上移除,它只是被标记成已删除(逻辑删除)。

在 Postman 中,向 ES 服务器发 DELETE 请求 : http://127.0.0.1:9200/shopping/_doc/1

HTTP-条件查询 & 分页查询 & 查询排序

条件查询

假设有以下文档内容,(在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search)

URL带参查询

查找category为小米的文档,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search?q=category:小米

上述为URL带参数形式查询,这很容易让不善者心怀恶意,或者参数值出现中文会出现乱码情况。为了避免这些情况,我们可用使用带JSON请求体请求进行查询。

请求体带参查询

接下带JSON请求体,还是查找category为小米的文档,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "query":{ "match":{ "category":"小米" } } }

带请求体方式的查找所有内容

查找所有文档内容,也可以这样,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "query":{ "match_all":{} } }

查询指定字段

如果你想查询指定字段,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "query":{ "match_all":{} }, "_source":["title"] }

分页查询

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "query":{ "match_all":{} }, "from":0, "size":2 }

查询排序

如果你想通过排序查出价格最高的手机,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "query":{ "match_all":{} }, "sort":{ "price":{ "order":"desc" } } }

HTTP-多条件查询 & 范围查询

多条件查询

假设想找出小米牌子,价格为3999元的。(must相当于数据库的 &&)

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "query":{ "bool":{ "must":[{ "match":{ "category":"小米" } },{ "match":{ "price":3999.00 } }] } } }

假设想找出小米和华为的牌子。(should相当于数据库的 || )

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"query":{
"bool":{
"should":[{
"match":{
"category":"小米"
}
},{
"match":{
"category":"华为"
}
}]
},
"filter":{
"range":{
"price":{
"gt":2000
}
}
}
}
}

范围查询

假设想找出小米和华为的牌子,价格大于2000元的手机。

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"query":{
"bool":{
"should":[{
"match":{
"category":"小米"
}
},{
"match":{
"category":"华为"
}
}],
"filter":{
"range":{
"price":{
"gt":2000
}
}
}
}
}
}

HTTP-全文检索 & 完全匹配 & 高亮查询

全文检索

这功能像搜索引擎那样,如品牌输入“小华”,返回结果带回品牌有“小米”和华为的。

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "query":{ "match":{ "category" : "小华" } } }

完全匹配

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "query":{ "match_phrase":{ "category" : "为" } } }

高亮查询

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
2
3
4
5
6
7
8
9
10
11
12
{
"query":{
"match_phrase":{
"category" : "为"
}
},
"highlight":{
"fields":{
"category":{}//<----高亮这字段
}
}
}

HTTP-聚合查询

聚合允许使用者对 es 文档进行统计分析,类似与关系型数据库中的 group by,当然还有很多其他的聚合,例如取最大值max、平均值avg等等。

接下来按price字段进行分组:

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "aggs":{//聚合操作 "price_group":{//名称,随意起名 "terms":{//分组 "field":"price"//分组字段 } } } }

上面返回结果会附带原始数据的。若不想要不附带原始数据的结果,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "aggs":{ "price_group":{ "terms":{ "field":"price" } } }, "size":0 }

若想对所有手机价格求平均值

在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:

1
{ "aggs":{ "price_avg":{//名称,随意起名 "avg":{//求平均 "field":"price" } } }, "size":0 }

HTTP-映射关系

有了索引库,等于有了数据库中的 database。

接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。

创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型下有哪些字段,每个字段有哪些约束信息,这就叫做映射(mapping)。

先创建一个索引:
PUT http://127.0.0.1:9200/user

创建映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 # PUT http://127.0.0.1:9200/user/_mapping

{
"properties": {
"name":{
"type": "text",
"index": true
},
"sex":{
"type": "keyword",
"index": true
},
"tel":{
"type": "keyword",
"index": false
}
}
}

查询映射
GET http://127.0.0.1:9200/user/_mapping

增加数据

1
#PUT http://127.0.0.1:9200/user/_create/1001 { "name":"小米", "sex":"男的", "tel":"1111" }

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!