八、ES中高级查询
1、查询方式
ES官方提供了两种检索方式:一种是通过URL参数进行搜索,另一种是通过DSL进行搜索。官方更推荐使用第二种方式,第二种方式是基于传递JSON作为请求体格式与ES进行交互,这种方式更强大,更简洁。
2、测试数据
# 1、删除索引
DELETE /ems
# 2、创建索引并指定类型
PUT /ems
{
"mappings":{
"emp":{
"properties":{
"name":{
"type":"keyword"
}.
"age":{
"type":"integer"
},
"bir":{
"type":"date"
},
"content":{
"type":"text"
},
"address":{
"type":"keyword"
}
}
}
}
}
# 3、插入测试数据
PUT /ems/emp/_bulk
{"index":{}}
{"name":"小黑","age":23,"bir":"2020-12-12","content":"未开发团队选择一款优秀的MVC框架是件难事儿,在众多可行的方案中抉择需要很高的经验和水平","address":"北京"}
{"index":{}}
{"name":"王小黑","age":24,"bir":"2020-12-12","content":"Spring框架是一个分层架构,由7个定义良好的模块组成,spring模块构建在核心容器之上,核心容器定义了创建、配置和管理bean的方式","address":"上海"}
{"index":{}}
{"name":"张小五","age":8,"bir":"2020-12-12","content":"Spring Cloud 作为Java语言的微服务框架,它依赖于SpringBoot,又快速开发,持续较夫和容易部署等特点,Spring Cloud 的组件非常多,涉及微服务的方方面面,并在开源社区Spring和Netflix,pivotal两大公司的推动下越来越完善","address":"无锡"}
{"index":{}}
{"name":"win7","age":9,"bir":"2020-12-12","content":"Spring的目标是致力于全方位的简化Java开发,这势必引出更多的解释,Spring是如何简化Java开发的?","address":"南京"}
{"index":{}}
{"name":"梅超风","age":43,"bir":"2020-12-12","content":"Redis是一个开源的使用ANSI C语言编写,支持网络,可基于内存亦可持久化的日志型,key-value数据库,并提供多种语言API","address":"杭州"}
{"index":{}}
{"name":"张无忌","age":59,"bir":"2020-12-12","content":"ElasticSearch是一个基于Lucene的搜索服务器,他提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口","address":"北京"}
3、URL查询
GET /ems/emp/_search?q=*&sort=age:asc
# _search 搜索的APi
# q=* 匹配所有文档
# sort 以结果中的指定字段排序
4、DSL查询
GET /ems/emp/_search
{
"query":{"match_all":{}},
"sort":[
{
"age":{
"order":"asc"
}
}
]
}
# 等价于上面URL检索的方式
5、DSL高级查询(Query)
查询所有(match_all)
match_all关键字:返回索引中的全部文档
GET /ems/emp/_search
{
"query":{"match_all":{}}
}
查询结果中返回的指定条数(size)
size关键字:指定查询结果中返回指定条数,默认返回值10条
GET /ems/emp/_search
{
"query":{"match_all":{}},
"size":1
}
分页查询(from)
from关键字:用来指定起始返回位置,和size关键字连用可实现分页效果
GET /ems/emp/_search
{
"query":{"match_all":{}},
"sort":[
{
"age":{
"order":"desc"
}
}
],
"size":2,
"from":1
}
查询结果中返回指定字段(_source)
_source关键字:是一个数组,在数组中可以用来显示展示哪些字段
GET /ems/emp/_search
{
"query":{"match_all":{}}
"_source":["account_number","balance"]
}
分词查询(match)
match关键字:会根据你的查询词进行分词
NOTE:好像match不管字段类型都会自动分词,term会根据字段的类型来决定是否分词
GET /ems/emp/_search
{
"query":{
"match":{
"address":"北京"
}
}
}
短语匹配(match_phrase)
match_phrase关键字:查询分析文本并根据分析的文本创建一个短语查询。match_phrase 会将检索关键词分词。match_phrase的分词结果必须在被检索字段的分词中都包含,而且顺序必须相同,而且默认必须都是连续的。
NOTE:还有一个match_phrase_prefix关键字,会对最后一个分词进行前缀扫描,导致始终要扫描大量索引,性能可能很差,这里就不记录了
#假设有四条数据
#{ "id" : 1,"content":"关注我,系统学编程" }
#{ "id" : 2,"content":"系统学编程,关注我" }
#{ "id" : 3,"content":"系统编程,关注我" }
#{ "id" : 4,"content":"关注我,间隔系统学编程" }
# 使用match_phrase查询,ik_smart分词
GET /tehero_index/_doc/_search
{
"query": {
"match_phrase": {
"content.ik_smart_analyzer": {
"query": "关注我,系统学"
}
}
}
}
#结果只有id为1的能够匹配,但是使用match查询则可以获取所有数据
分析:上面的例子使用的分词器是ik_smart,所以检索词“关注我,系统学”会被分词为3个Token【关注、我、系统学】;而文档1、文档2和文档4 的content被分词后都包含这3个关键词,但是只有文档1的Token的顺序和检索词一致,且连续。所以使用 match_phrase 查询只能查询到文档1(ps:文档2 Token顺序不一致;文档4 Token不连续;文档3 Token没有完全包含)。使用 match查询可以查询到所有文档,是因为所有文档都有【关注、我】这两个Token。
#match_phrase 核心参数:slop 参数-Token之间的位置距离容差值
# 将上面的 match_phrase 查询新增一个 slop参数
GET /tehero_index/_doc/_search
{
"query": {
"match_phrase": {
"content.ik_smart_analyzer": {
"query": "关注我,系统学",
"slop":1
}
}
}
}
# 结果:文档1和文档4都被检索出来
# 原因:关注我,间隔系统学编程 会被分词为{关注、我、间隔、系统、学、编程},我与系统学之间间隔为1
关键词查询(term)
term关键字:用来使用关键词查询
GET /ems/emp/_search
{
"query":{
"term":{
"address":{
"value":"北京"
}
}
}
}
# Note1:通过使用term查询得知ES中默认使用分词器为标准分词器(standard Analyzer),标准分词器对于英文单词分词,对于中文单字分词
# Note2:通过使用term查询得知,在ES的Mapping Type中keyword、date、integer、long、double、boolean、ip这些类型不分词,只有text类型分词
范围查询(range)
range关键字:用来指定查询指定范围的围挡
GET /ems/emp/_search
{
"query":{
"range":{
"age":{
"gte":8,
"lte":38
}
}
}
}
前缀查询(prefix)
prefix关键字:用来检索含有指定前缀的关键词的相关文档
GET /ems/emp/_search
{
"query":
"prefix":{
"content":{
"value":"redis"
}
}
}
通配符查询(wildcard)
wildcard关键字:通配符查询 ?用来表示一个任意字符 *用来匹配多个任意字符
GET /ems/emp/_search
{
"query":{
"wildcard":{
"content":{
"value":"re*"
}
}
}
}
多id查询(ids)
ids关键字:值为数组类型,用来根据一组id获取多个对应的文档
GET /ems/emp/_search
{
"query":{
"ids":{
"values":["aod12doj12ihdd1d","dkno1idiosnkf123"]
}
}
}
模糊查询(fuzzy)
注意:
此模糊查询非关系型数据库的模糊查询
fuzzy关键字:用来模糊查询含有指定关键字的文档,注意:允许出现的错误必须在0~2之间
最大错误编辑距离由文本的词长决定
如果文本长度为0~2 则不允许出现错误
如果文本长度为3~5 则允许由一个错误
如果文本长度大于5 则允许由两个错误
GET /ems/emp/_search
{
"query":{
"fuzzy":{
"content":"spoong"
}
}
}
# 本意查询spring,因为spring字符为6个所以允许错误2个字符(最大错误距离两个)
布尔查询(bool)
bool关键字:用来组合多个条件实现复杂查询
must:相当于 && 同时成立
should:相当于 || 成立一个就行
must_not:相当于 !不能满足任何一个
GET /ems/emp/_search
{
"query":{
"bool":{
"must":[
{
"range":{
"age":{
"gte":8,
"lte":30
}
}
}
]
}
},
"must_not":[
{
"wildcard":{
"content":{
"value":"redi?"
}
}
}
]
}
高亮查询(highlight)
highlight关键字:可以让符合条件的文档中的关键字高亮
GET /ems/emp/_search
{
"query":{
"term":{
"content":{
"value":"redis"
}
}
},
"highlight":{
"fields":{
"*":{}
}
}
}
# 默认高亮标签为<em></em>
# 也可以自定义高亮html标签,在highlight中使用pre_tags和post_tags
GET /ems/emp/_search
{
"query":{
"term":{
"content":"框架"
}
},
"highlight":{
"pre_tags":["<span style='color:red'>"],
"post_tags":["</span>"],
"fields":{
"*":{}
}
}
}
# 多字段高亮 使用require_field_match开启多个字段高亮
GET /ems/emp/_search
{
"query":{
"term":{
"content":"框架"
}
},
"hightlight":{
"pre_tags":["<span style='color:red'>"],
"post_tags":["</span>"],
"require_field_match":"false",
"fields":{
"*":{} # *代表全部字段高亮
}
}
}
多字段查询(multi_match)
注意:使用这种方式进行查询时,为了更好获取搜索结果,在查询过程中会先将查询条件根据当前的分词器分词之后进行查询
GET /ems/emp/_search
{
"query":{
"multi_match":{
"query":"中国",
"fields":["name","content"] #这里写要检索的指定字段
}
}
}
多字段分词查询(query_string)
注意:使用这种方式进行查询时,为了更好获取搜索结果,在查询过程中会先将查询条件根据当前的分词器分词之后进行查询,与上面不同的是,你可以选择分词器
GET /dangdand/book/_search
{
"query":{
"query_string":{
"query":"中国人民共和国".
"analyzer":"ik_max_word",
"fields":["name","content"]
}
}
}
过滤查询(Filter Query)
1、过滤查询
其实准确来说,ES中的查询操作分为2中,
查询(Query)
和过滤(filter)
,查询即是之前得到的query查询,它(查询)默认会计算每个返回文档的得分,然后根据得分排序
,而过滤(filter)直会筛选出符合的文档,并不计算得分,且它可以缓存文档,所以,单从性能考虑,过滤比查询更快
2、过滤语法
必须使用bool表达式将两种query组合在一起
注意:当filterQuery和query组合使用时先执行filterQuery中的语句,然后再去执行query中的语句
# 先过滤年龄大于等于10的再来查询
GET /ems/emp/_search
{
"query":{
"bool":{
"must":{
{"match_all":{}}
},
"filter":{
"range":{
"age":{
"gte":10
}
}
}
}
}
}
3、常见的过滤器类型
# 1、使用term过滤 先过滤出content为框架的数据后再去查询name为小黑的文档
GET /ems/emp/_search
{
"query":{
"bool":{
"must":[
{
"term":{
"name":{
"value":"小黑"
}
}
}
],
"filter":{
"term":{
"content":"框架"
}
}
}
}
}
# 2、使用terms过滤 先过滤出content为大黑或者大白的文档再去查询name为小黑的文档数据
GET /dangdang/book/_search
{
"query":{
"bool":{
"must":[
{
"term":{
"name":{
"value":"小黑"
}
}
}
],
"filter":{
"terms":{
"content":["大黑","大白"]
}
}
}
}
}
# 3、ranage filter过滤 先过滤age在7到20岁的文档,再去查询name为小黑的数据
GET /ems/emp/_search
{
"query":{
"bool":{
"must":[
"term":{
"name":{
"value":"小黑"
}
}
],
"filter":{
"range":{
"age":{
"gte":7,
"lte":20
}
}
}
}
}
}
# 4、exists filter 过滤存在指定字段,获取字段不为空的索引记录使用 过滤存在字段aaa的文档再去查询name为小黑的数据
GET /ems/emp/_search
{
"query":{
"bool":{
"must":[
"term":{
"name":{
"value":"小黑"
}
}
],
"filter":{
"exists":{
"field":"aaa"
}
}
}
}
}
# 5、ids filter 过滤含有指定字段的索引记录 先过滤出id为1、2、3的数据再去查询名字为小黑的数据
GET /ems/emp/_search
{
"query":{
"bool":{
"must":[
"term":{
"name":{
"value":"小黑"
}
}
],
"filter":{
"ids":{
"values":["1","2","3"]
}
}
}
}
}
ElasticSearch学习笔记(1)· ES基本概念
ElasticSearch学习笔记(2)· 基于Kibana的基本CRUD
ElasticSearch学习笔记(3)· ES高级检索(query)
ElasticSearch学习笔记(4)· ES IK分词器
ElasticSearch学习笔记(5)· Java操作Elasticsearch6.2.4
ElasticSearch学习笔记(6)· Java操作Elasticsearch7.6.1
ElasticSearch学习笔记(7)· Springboot+SpringData操作ES
ElasticSearch学习笔记(8)· ES集群的搭建