二、ElasticSearch基本操作
1、RESTful
- REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。Web 应用程序最重要的 REST 原则是,客户端和服务器之间的交互在请求之间是无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服务器在请求之间的任何时间点重启,客户端不会得到通知。此外,无状态请求可以由任何可用服务器回答,这十分适合云计算之类的环境。客户端可以缓存数据以改进性能。
- 在服务器端,应用程序状态和功能可以分为各种资源。资源是一个有趣的概念实体,它向客户端公开。资源的例子有:应用程序对象、数据库记录、算法等等。每个资源都使用 URI (Universal Resource Identifier) 得到一个唯一的地址。所有资源都共享统一的接口,以便在客户端和服务器之间传输状态。使用的是标准的 HTTP 方法,比如 GET、PUT、POST 和DELETE。
- 在 REST 样式的 Web 服务中,每个资源都有一个地址。资源本身都是方法调用的目标,方法列表对所有资源都是一样的。这些方法都是标准方法,包括 HTTP GET、POST、PUT、DELETE,还可能包括 HEAD 和 OPTIONS。简单的理解就是,如果想要访问互联网上的资源,就必须向资源所在的服务器发出请求,请求体中必须包含资源的网络路径,以及对资源进行的操作(增删改查)。
2、Es的数据格式
- Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档。为了方便大家理解,我们将 Elasticsearch 里存储文档数据和关系型数据库 MySQL 存储数据的概念进行一个类比
- ES 里的 Index 可以看做一个库,而 Types 相当于表,Documents 则相当于表的行。这里 Types 的概念已经被逐渐弱化,Elasticsearch 6.X 中,一个 index 下已经只能包含一个type,Elasticsearch 7.X 中, Type 的概念已经被删除了。
3、Http操作
-
索引操作
-
创建索引
-
对比关系型数据库,创建索引就等同于创建数据库
-
在 Postman 中,向 ES 服务器发 PUT 请求 :http://127.0.0.1:9200/class
-
请求后,服务器返回响应
-
-
{ "acknowledged"【响应结果】: true, # true 操作成功 "shards_acknowledged"【分片结果】: true, # 分片操作成功 "index"【索引名称】: "shopping" } # 注意:创建索引库的分片数默认 1 片,在 7.0.0 之前的 Elasticsearch 版本中,默认 5 片
-
-
如果重复添加索引,会返回错误信息
-
-
查看所有索引
- 在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/_cat/indices?v
- 这里请求路径中的_cat 表示查看的意思,indices 表示索引,所以整体含义就是查看当前 ES服务器中的所有索引,就好像 MySQL 中的 show tables 的感觉,服务器响应结果如下:
- 在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/_cat/indices?v
-
查看单个索引
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/class
-
查看索引向 ES 服务器发送的请求路径和创建索引是一致的。但是 HTTP 方法不一致。这里可以体会一下 RESTful 的意义,请求后,服务器响应结果如下:
-
-
{ "shopping"【索引名】: { "aliases"【别名】: {}, "mappings"【映射】: {}, "settings"【设置】: { "index"【设置 - 索引】: { "creation_date"【设置 - 索引 - 创建时间】: "1627635260805", "number_of_shards"【设置 - 索引 - 主分片数量】: "1", "number_of_replicas"【设置 - 索引 - 副分片数量】: "1", "uuid"【设置 - 索引 - 唯一标识】: "SH-TMF4IS7-z1OlfuA7soQ", "version"【设置 - 索引 - 版本】: { "created": "7080099" }, "provided_name"【设置 - 索引 - 名称】: "class" } } } }
-
-
-
删除索引
- 在 Postman 中,向 ES 服务器发 DELETE 请求 :http://127.0.0.1:9200/class
- 重新访问索引时,服务器返回响应:索引不存在
- 在 Postman 中,向 ES 服务器发 DELETE 请求 :http://127.0.0.1:9200/class
-
-
文档操作
-
-
创建文档
索引已经创建好了,接下来我们来创建文档,并添加数据。这里的文档可以类比为关系型数据库中的表数据,添加的数据格式为 JSON 格式
-
在 Postman 中,向 ES 服务器发 POST 请求 :http://127.0.0.1:9200/class**/_doc**
-
请求体内容为:
-
{ "name":"张三", "age":18 }
-
-
-
此处发送请求的方式必须为 POST,不能是 PUT,否则会发生错误
-
Post方法,服务器响应结果如下:
-
-
{ "_index"【索引】: "class", "_type"【类型-文档】: "_doc", "_id"【唯一标识】: "yiGm9noBj0KWx1uYq8K1", #可以类比为 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/class/_doc/1
-
此处需要注意:如果增加数据时明确数据主键,那么请求方式也可以为 PUT
-
-
查看文档
查看文档时,需要指明文档的唯一性标识,类似于 MySQL 中数据的主键查询
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/class**/_doc/1**
-
查询成功后,服务器响应结果:
-
-
{ "_index"【索引】: "class", "_type"【文档类型】: "_doc", "_id": "1", "_version": 1, "_seq_no": 2, "_primary_term": 1, "found": true, "_source"【文档源信息】: { "name": "李四", "age": 24 } }
-
-
-
修改文档
和新增文档一样,输入相同的 URL 地址请求,如果请求体变化,会将原有的数据内容覆盖
-
在 Postman 中,向 ES 服务器发 POST 请求 :http://127.0.0.1:9200/class**/_doc/1**
-
请求体内容为:
-
{ "name":"李四123", "age":24 }
-
-
-
修改成功后,服务器响应结果:
-
-
{ "_index": "class", "_type": "_doc", "_id": "1", "_version"【版本】: 2, "result"【结果】: "updated", # updated 表示数据被更新 "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 3, "_primary_term": 1 }
-
-
-
修改字段
修改数据时,也可以只修改某一给条数据的局部信息
-
在 Postman 中,向 ES 服务器发 POST 请求 :http://127.0.0.1:9200/class/_update/1
-
请求头内容:
-
{ "doc": { "age": 1 } }
-
-
-
修改成功后,服务器响应结果:
-
根据唯一性标识,查询文档数据,文档数据已经更新
-
-
删除文档
删除一个文档不会立即从磁盘上移除,它只是被标记成已删除(逻辑删除)。
-
在 Postman 中,向 ES 服务器发 DELETE 请求 :http://127.0.0.1:9200/class**/_doc/1**
-
删除成功,服务器响应结果:
-
-
{ "_index": "class", "_type": "_doc", "_id": "1", "_version"【版本】: 4, #对数据的操作,都会更新版本 "result"【结果】: "deleted", # deleted 表示数据被标记为删除 "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 5, "_primary_term": 1 }
-
-
删除后再查询当前文档信息
-
如果删除一个并不存在的文档
-
-
-
{ "_index": "class", "_type": "_doc", "_id": "1", "_version": 1, "result"【结果】: "not_found", # not_found 表示未查找到 "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 6, "_primary_term": 1 }
-
-
-
条件删除文档
一般删除数据都是根据文档的唯一性标识进行删除,实际操作时,也可以根据条件对多条数据进行删除
-
向 ES 服务器发 POST 请求 :http://127.0.0.1:9200/class/_delete_by_query
-
请求体内容为:
-
{ "query" : { "match" : { "age" : 3 } } }
-
-
-
删除成功后,服务器响应结果:
-
-
{ "took"【耗时】: 85, "timed_out"【是否超时】: false, "total"【总数】: 3, "deleted"【删除数量】: 3, "batches": 1, "version_conflicts": 0, "noops": 0, "retries": { "bulk": 0, "search": 0 }, "throttled_millis": 0, "requests_per_second": -1.0, "throttled_until_millis": 0, "failures": [] }
-
-
-
-
-
映射操作
接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型下有哪些字段,每个字段有哪些约束信息,这就叫做映射(mapping)。
-
创建映射
-
在 Postman 中,向 ES 服务器发 PUT 请求 :http://127.0.0.1:9200/student**/_mapping**
-
请求体内容为:
-
{ "properties" : { "name" : { "type" : "text", "index" : true }, "sex" : { "type" : "text", "index" : false }, "age" : { "type" : "long", "index" : false } } }
-
-
-
服务器响应结果如下:
-
映射数据说明:
- 字段名:任意填写,下面指定许多属性,例如:title、subtitle、images、price
- type:类型,Elasticsearch 中支持的数据类型非常丰富,说几个关键的:
- String 类型,又分两种:
- text:可分词
- keyword:不可分词,数据会作为完整字段进行匹配
- Numerical:数值类型,分两类
- 基本数据类型:long、integer、short、byte、double、float、half_float
- 浮点数的高精度类型:scaled_float
- Date:日期类型
- Array:数组类型
- Object:对象
- index:是否索引,默认为 true,也就是说你不进行任何配置,所有字段都会被索引。
- true:字段会被索引,则可以用来进行搜索
- alse:字段不会被索引,不能用来搜索
- store:是否将数据进行独立存储,默认为 false
- 原始的文本会存储在_source 里面,默认情况下其他提取出来的字段都不是独立存储的,是从_source 里面提取出来的。当然你也可以独立的存储某个字段,只要设置 “store”: true 即可,获取独立存储的字段要比从_source 中解析快得多,但是也会占用更多的空间,所以要根据实际业务需求来设置。
- analyzer:分词器,这里的 ik_max_word 即使用 ik 分词器,后面会有专门的章节学习
- String 类型,又分两种:
-
-
查看映射
- 在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student**/_mapping**
- 服务器响应结果如下:
- 在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student**/_mapping**
-
索引映射关联
-
在 Postman 中,向 ES 服务器发 PUT 请求 :http://127.0.0.1:9200/student1
-
请求体内容:
-
{ "setting" : {}, "mappings" : { "properties" : { "name" : { "type" : "test", "index" : true }, "sex" : { "type" : "test", "index" : false }, "age" : { "type" : "long", "index" : false } } } }
-
-
-
服务器响应结果如下:
-
-
-
高级查询
Elasticsearch 提供了基于 JSON 提供完整的查询 DSL 来定义查询
-
查询所有文档
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
{ "query": { "match_all": {} } } # "query":这里的 query 代表一个查询对象,里面可以有不同的查询属性 # "match_all":查询类型,例如:match_all(代表查询所有), match,term , range 等等 # {查询条件}:查询条件会根据类型的不同,写法也有差异
-
-
-
服务器响应结果如下:
-
-
-
{ "took【查询花费时间,单位毫秒】" : 1116, "timed_out【是否超时】" : false, "_shards【分片信息】" : { "total【总数】" : 1, "successful【成功】" : 1, "skipped【忽略】" : 0, "failed【失败】" : 0 }, "hits【搜索命中结果】" : { "total"【搜索条件匹配的文档总数】: { "value"【总命中计数的值】: 3, "relation"【计数规则】: "eq" # eq 表示计数准确, gte 表示计数不准确 }, "max_score【匹配度分值】" : 1.0, "hits【命中结果集合】" : [ ... } ] } }
-
-
-
匹配查询
match 匹配类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是 or 的关系
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
请求体内容:
-
{ "query" : { "match" : { "name" : "张三" } } }
-
-
-
服务器响应结果为:
-
-
字段匹配查询
multi_match 与 match 类似,不同的是它可以在多个字段中查询。
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
请求体内容:
-
{ "query": { "multi_match": { "query": "张三", "fields": ["name"] } } }
-
-
-
服务器响应结果:
-
-
关键字精确查询
term 查询,精确的关键词匹配查询,不对查询条件进行分词
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
请求头内容:
-
{ "query": { "term": { "name": { "value": "zhangsan" } } } }
-
-
-
服务器响应结果:
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s8NPBXUp-1627719867392)(E:\资料\博客\Java\ElasticSearch\image\关键字精确查询2.png)]
-
-
多关键字精确查询.
terms 查询和 term 查询一样,但它允许你指定多值进行匹配。
如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件,类似于 mysql 的 in
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
{ "query" : { "terms" : { "name" : ["zhangsan", "lisi"] } } }
-
-
-
服务器响应结果:
-
-
指定查询字段
默认情况下,Elasticsearch 在搜索的结果中,会把文档中保存在_source 的所有字段都返回。
如果我们只想获取其中的部分字段,我们可以添加_source 的过滤
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "_source" : ["name", "nickname"], "query" : { "terms" : { "name" : ["zhangsan", "lisi"] } } }
-
-
-
服务器响应结果:
-
-
过滤字段
-
我们也可以通过:
- includes:来指定想要显示的字段
- excludes:来指定不想要显示的字段
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "_source" : { "includes" : ["name", "nickname"] }, "query" : { "terms" : { "name" : ["zhangsan", "lisi"] } } }
-
-
-
服务器响应结果:
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求头内容 { "_source" : { "excludes" : ["name", "nickname"] }, "query" : { "terms" : { "name" : ["zhangsan", "lisi"] } } }
-
-
-
服务器响应结果:
-
-
组合查询
bool
把各种其它查询通过must
(必须 )、must_not
(必须不)、should
(应该)的方式进行组合-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "query" : { "bool" : { "must" : [ { "match" : { "name" : "zhangsan" } } ], "must_not" : [ { "match" : { "age" : "40" } } ], "should" : [ { "match" : { "sex" : "男" } } ] } } }
-
-
服务器响应结果:
-
-
范围查询
range 查询找出那些落在指定区间内的数字或者时间。range 查询允许以下字符
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "query" : { "range" : { "age" : { "gte" : 30, "lte" : 35 } } } }
-
-
-
服务器响应结果:
-
-
模糊查询
返回包含与搜索字词相似的字词的文档。编辑距离是将一个术语转换为另一个术语所需的一个字符更改的次数。这些更改可以包括:
- 更改字符(box → fox)
- 删除字符(black → lack)
- 插入字符(sic → sick)
- 转置两个相邻字符(act → cat)
为了找到相似的术语,fuzzy 查询会在指定的编辑距离内创建一组搜索词的所有可能的变体或扩展。然后查询返回每个扩展的完全匹配。
通过 fuzziness 修改编辑距离。一般使用默认值 AUTO,根据术语的长度生成编辑距离。
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "query" : { "fuzzy" : { "name" : { "value" : "zhangsan" } } } }
-
-
-
服务器响应结果:
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "query" : { "fuzzy" : { "name" : { "value" : "zhangsan", "fuzziness" : 0 } } } }
-
-
-
服务器响应结果:
-
单字段排序
sort 可以让我们按照不同的字段进行排序,并且通过 order 指定排序的方式。desc 降序,asc升序。
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "query" : { "match_all" : { } }, "sort" : [{ "age" : { "order" : "desc" } }] }
-
-
-
服务器响应结果:
-
-
多字段排序
假定我们想要结合使用 age 和 _score 进行查询,并且匹配的结果首先按照年龄排序,然后按照相关性得分排序
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "query" : { "match_all" : { } }, "sort" : [ { "age" : { "order" : "desc" } }, { "_score" : { "order" : "desc" } } ] }
-
-
-
服务器响应结果:
-
-
高亮查询
在进行关键字搜索时,搜索出的内容中的关键字会显示不同的颜色,称之为高亮。
Elasticsearch 可以对查询内容中的关键字部分,进行标签和样式(高亮)的设置。
在使用 match 查询的同时,加上一个 highlight 属性:
- pre_tags:前置标签
- post_tags:后置标签
- fields:需要高亮的字段
- title:这里声明 title 字段需要高亮,后面可以为这个字段设置特有配置,也可以空
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "query" : { "match" : { "name" : "zhangsan" } }, "highlight" : { "pre_tags" : "<font color = 'red'>", "post_tags" : "</font>", "fields" : { "name" : {} } } }
-
-
-
服务器响应结果:
-
分页查询
from:当前页的起始索引,默认从 0 开始。 from = (pageNum - 1) * size
size:每页显示多少条
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "query" : { "match_all" : { } }, "sort" : [ { "age" : { "order" : "desc" } } ], "from" : 0, "size" : 2 }
-
-
-
服务器响应结果:
-
-
聚合查询
聚合允许使用者对 es 文档进行统计分析,类似与关系型数据库中的 group by,当然还有很多其他的聚合,例如取最大值、平均值等等。
对某个字段取最大值 max
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "aggs" : { "max_age" : { "max" : {"field" : "age"} } }, "size" : 0 }
-
-
-
服务器响应结果:
对某个字段取最小值 min
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "aggs" : { "min_age" : { "min" : {"field" : "age"} } }, "size" : 0 }
-
-
-
服务器响应结果:
对某个字段求和 sum
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "aggs" : { "sum_age" : { "sum" : {"field" : "age"} } }, "size" : 0 }
-
-
-
服务器响应结果:
对某个字段取平均值 avg
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "aggs" : { "avg_age" : { "avg" : {"field" : "age"} } }, "size" : 0 }
-
-
-
服务器响应结果:
对某个字段的值进行去重之后再取总数
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "aggs" : { "distinct_age" : { "cardinality" : {"field" : "age"} } }, "size" : 0 }
-
-
-
服务器响应结果:
Stats 聚合
stats 聚合,对某个字段一次性返回 count,max,min,avg 和 sum 五个指标
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "aggs" : { "stats_age" : { "stats" : {"field" : "age"} } }, "size" : 0 }
-
-
-
服务器响应结果:
-
-
桶聚合查询
桶聚和相当于 sql 中的 group by 语句
terms 聚合,分组统计
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "aggs" : { "age_groupby" : { "terms" : {"field" : "age"} } }, "size" : 0 }
-
-
-
服务器响应结果:
在 terms 分组下再进行聚合
-
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
-
#请求体内容 { "aggs" : { "age_groupby" : { "terms" : {"field" : "age"}, "aggs" : { "sum_age" : { "sum" : {"field" : "age"} } } } }, "size" : 0 }
-
-
-
服务器响应结果:
-
-