白日梦的Elasticsearch实战笔记,ES账号免费借用、32个查询案例、15个聚合案例、7个查询优化技巧。(二)
下面一起看一下有哪些query dsl的使用方式。 查询的返回值和上面我们一起看的那个是一样的 所以下面的重点是怎么查 而不是怎么看返回值哈
1、查询指定index下的全部doc
# _search是关键字 下文基本每个查询都会有它 不再赘述了哈 GET /your_index/your_type/_search query : { match_all : {} } }
2、针对name字段进行全文检索 match查询
ES会将用户将输入的字符串通过分词器拆解开 然后去倒排索引中扫描匹配 下一篇文章白日梦的笔记会重新杀回ES涉及的核心概念 包括这个倒排索引 。在倒排索引中哪怕匹配上了一个也会将结果返回。
GET /yourIndex/yourType/_search query : { # match表示全文检索 所以白日梦会被分词成 白日、梦、白日梦 # 也就是说当前的match会匹配出name中有“白日” 或者“梦” 或者“白日梦”的doc match : { name : 白日梦 # 实际上 match query底层会被转换成下面的格式进行检索 # bool :{ # should :[ # { term :{ title : 白日 }}, # { term :{ title : 白日梦 }}, # { term :{ title : 梦 }} #
3、全文检索 手动控制全文检索的精度
GET /your_index/your_type/_search query : { match : { name :{ query : bairi meng , # and表示 只有同时出现bairi meng两个词的doc才会被命中 # 如果不加and限制 则bairi和meng之间是或的关系 只要出现一个就行 operator : and , # 添加上operator 操作会被ES转换成下面的格式 将上面的should转换成must # bool :{ # must :[ # { term :{ title : bairi }}, # { term :{ title : meng }} # }
4、去掉全文检索的长尾
# 去长尾 GET /your_index/your_type/_search query : { match : { name :{ query : 欢迎关注白日梦 , operator : and , # 上面的query可能被分词成 欢迎、关注、白日梦、欢迎关注、关注白日梦这五个词。 # 默认来说只要命中其中的一个词 那个doc就会被返回 所以有长尾现象。 # 去长尾 控制至少命中3/4个词的doc才算是真正命中。 minimum_should_match : 75% # 添加上 minimum_should_match 操作会被ES转换成下面的格式 # bool :{ # should :[ # { term :{ title : 白日 }}, # { term :{ title : 梦 }} # minimum_should_match :3 #
5、全文检索 通过boost控制权重。
如下Case 要求doc的name字段必须包含 “关注” 于此同时 如果doc的name字段中包含 “白日梦” 则将这个doc的权重提高为3 如果name字段中包含了“公众号” 再提高它的权重2。经过这样的处理 name字段中包含 “关注白日梦公众号” 的doc的权重就最高 它在搜索结果中的排名就越靠前。
GET /your_index/your_type/_search query : { bool :{ must :{ match : { name :{ # 默认情况下 所有字段的权重都是样的 都是1 query : 关注 , should :[ match : { name :{ query : 白日梦 , # 将name字段的权重提升成3 boost :3 match : { name :{ query : 公众号 , # 将name字段的权重提升成3 # 默认情况下 所有字段的权重都是样的 都是1 boost :2 }
6、稍微复杂一点的多条件查询:bool查询
GET /your_index/your_type/_search query : { # 比如你的查询比较复杂 涉及到很多的子查询 那你可以考虑通过bool查询包裹这些子查询 # 每一个子查询都会计算出这个doc针对于它这种查询得到的相关性得分。 # 最终由bool查询将这些得分合并为一个最终的得分 bool : { # 必须匹配到XXX 并且会得出相关性得分 # address中必须包含mill must : [ { match : { address : mill } }, # 在满足must的基础上 should条件不满足也可以 但是如果也匹配上了 相关性得分会增加 # 如果没有must的话 should中的条件必须满足一个 should : [{ match : { address : lane } }], must_not : [ # 一定不包含谁 { match : { address : mill } }, }
7、bool查询 去长尾。
# bool查询 去长尾 GET /your_index/your_type/_search query : { bool :{ should :[ match :{ name : 白日梦1 }, match :{ name : 白日梦2 }, match :{ name : 白日梦3 }, minimum_should_match :3 }
8、best fields策略 取多个query中得分最高的得分作为doc的最终得分。
一个query中是存在多个match的 我们称它为多字段查询 而且每个match都会贡献自己的相关性得分 也就是说doc最终的相关性得分是通过这多个match贡献的相关性得分通过一定的机制计算出来的。而且相关性得分越高 文档在搜索结果中就越靠前。
这时 如果你不希望让doc的最终得分是通过综合所有的match计算得出的 可以使用dis_max查询。它会取所有match中得分最高的match当作doc的最终得分。
GET /your_index/your_type/_search query : { # 这种用法不容忽略 # 直接取下面多个query中得分最高的query当成最终得分 dis_max : { queries :[ { match :{ name : 白日梦 }}, { match :{ content : 关注白日梦 }} }
9、基于 tie_breaker 优化dis_max
上面的Case中有提到这个dis_max查询 这个dis_max也是实现best field的关键 即 它会取所有match中得分最高的match当作doc的最终得分。
而这个例子中的tie_breaker会重新让dis_max考虑到其他field的得分影响 比如下面的0.4 表示最终的doc得分会考虑其他match的影响 但是它的影响会被弱化成原来的0.4。
GET /your_index/your_type/_search # 基于 tie_breaker 优化dis_max # tie_breaker可以使dis_max考虑其它field的得分影响 query : { # 直接取下面多个query中得分最高的query当成最终得分 # 这也是best field策略 dis_max : { queries :[ { match :{ name : 关注 }}, { match :{ content : 白日梦 }} tie_breaker :0.4 }
10、同时在你指定的多个字段中进行检索 multi_match
GET /your_index/your_type/_search # 查询多个 在下面指定的两个字段中检索含有 “this is a test“ 的doc query : { multi_match : { query : this is a test , fields : [ subject , message ] }
11、使用multi_match query简化dis_max
# 还是这个dis_max query 如下 GET /your_index/your_type/_search # 基于 tie_breaker 优化dis_max # tie_breaker可以使dis_max考虑其它field的得分影响 query : { # 直接取下面多个query中得分最高的query当成最终得分 # 这也是best field策略 dis_max : { queries :[ { match :{ name : 关注 }}, { match :{ content : 白日梦 }} tie_breaker :0.4 # 使用multi_match query简化写法如下 GET /your_index/your_type/_search query : { multi_match :{ query : 关注 白日梦 , # 指定检索的策略 best_fields 因为dis_max就是best field策略 type : best_fields , # content^2 表示增加权重 相当于 boost2 fields :[ name , content^2 ], tie_breaker :0.4, minimum_should_match :3 }
12、most field策略和上面说的best field策略是不同的 因为best field策略说的是 优先返回某个field匹配到更多关键字的doc。
优先返回有更多的field匹配到你给定的关键字的doc。而不是优先返回某个field完全匹配你给定关键字的doc
另外most_fields不支持使用minimum_should_match去长尾。
GET /your_index/your_type/_search # most_fields策略、优先返回命中更多关键词的doc # 如下从title、name、content中搜索包含“赐我白日梦”的doc query : { multi_match :{ query : 赐我白日梦 , # 指定检索的策略most_fields type : most_fields , fields :[ title , name , content ] }
13、cross_fields策略 如下Case
GET /your_index/your_type/_search query : { multi_match :{ query : golang java , # cross_fields 要求golang 必须在title或者在content中出现 # cross_fields 要求java 必须在title或者在content中出现 type : cross_fields , fields :[ title , content ] }
14、查询空
GET /your_index/your_type/_search query : { match_none : {} }
15、精确匹配
# 使用trem指定单个字段进行精确匹配 GET /your_index/your_type/_search # 精确匹配name字段为白日梦的doc query : { constant_score :{ filter :{ term : { name : 白日梦 # 使用terms指定在多个字段中进行精确匹配 # 下面的例子相当于SQL where name in ( tom , jerry ) GET /your_index/your_type/_search # 精确匹配 query : { constant_score :{ filter :{ terms : { 想搜索的字段名 :[ tom , jerry }
16、短语检索 要求doc的该字段的值和你给定的值完全相同 顺序也不能变 所以它的精确度很高 但是召回率低。
GET /your_index/your_type/_search # 短语检索 # 顺序的保证是通过 term position来保证的 # 精准度很高 但是召回率低 query : { # 只有name字段中包含了完整的 白日梦 这个doc才算命中 # 不能是单个 ”白日“ 也不能是单个的 “梦” 也不能是“白日xxx梦” # 要求 短语相连 且顺序也不能变 match_phrase : { name : 白日梦 }
17、提高短语检索的召回率
如果使用match_phase进行短语检索 本质上就是要求doc中的字段值和给定的值完全相同 即使是顺序不同也不行。但是为了提高召回率如你又想容忍短语匹配可以存在一定的误差 比如你希望搜索 “i love world” 时 能够搜索出 world love i
这时可以通过slop来实现这个功能 slop可以帮你让指定短语中的词最多经过slop次移动后如果能匹配某个doc 也把这个doc当作结果返回给用户。
GET /your_index/your_type/_search # 短语检索 query : { # 指定了slop就不再要求搜索term之间必须相邻 而是可以最多间隔slop距离。 # 在指定了slop参数的情况下 离关键词越近 移动的次数越少 relevance score 越高。 # match_phrase slop 和 proximity match 近似匹配作用类似。 # 平衡精准度和召回率。 match_phrase : { address : mill lane , # 指定搜索文本中的几个term经过几次移动后可以匹配到一个doc slop :2 }
18、混合使用match和match_phrase 平衡精准度和召回率
GET /your_index/your_type/_search # 混合使用match和match_phrase 平衡精准度和召回率 query : { bool : { must : { # 全文检索虽然可以匹配到大量的文档 但是它不能控制词条之间的距离 # 可能i love world在doc1中距离很近 但是它却被ES排在结果集的后面 # 它的性能比match_phrase和proximity高 match : { title : i love world should : { # 因为slop有个特性 词条之间间隔的越近 移动的次数越少 最终的得分就越高 # 于是可以借助match_phrase slop感知term position的功能 # 实现为距离相近的doc贡献分数 让它们靠前排列 match_phrase :{ title :{ query : i love world , slop :15 }
19、使用rescore_query重打分。提高精准度和召回率。
GET /your_index/your_type/_search # 重打分机制 query : { match :{ title :{ query : i love world , minimum_should_match : 50% # 对全文检索的结果进行重新打分 rescore :{ # 对全文检索的前50条进行重新打分 window_size :50 query : { # 关键字 rescore_query :{ # match_phrase slop 感知 term persition 贡献分数 match_phrase :{ title :{ query : i love world , slop :50 }
20、前缀匹配 搜索 user字段以 白日梦 开头的 doc
GET /your_index/your_type/_search # 前缀匹配 相对于全文检索 前缀匹配是不会对前缀进行分词的。 # 而且每次匹配都会扫描整个倒排索引 直到扫描完一遍才会停下来 # 前缀搜索不会计算相关性得分所有的doc的得分都是1 # 前缀越短能匹配到的doc就越多 性能越不好 query : { prefix : { user : 白日梦 } }
21、前缀搜索 添加权重
GET /your_index/your_type/_search # 前缀搜索 添加权重 query : { prefix : { name : { value : 白日梦 , boost : 2.0 }
22、通配符搜索
GET /your_index/your_type/_search # 通配符搜索 query : { wildcard : { title : 白日梦的*笔记 GET /your_index/your_type/_search # 通配符搜索 query : { wildcard : { title : { value : 白日梦的*笔记 , boost : 2.0 }
23、正则搜索
GET /your_index/your_type/_search # 正则搜索 query : { regexp :{ name.first :{ value : s.*y , boost :1.2 }
24、搜索推荐 match_phrase_prefix 最终实现的效果类似于百度搜索 当用户输入一个词条后 将其它符合条件的词条的选项推送出来。
match_phrase_prefix和match_phrase相似 但是区别是它会将最后一个term当作前缀 发起一次搜索。因此它也叫search time 搜索推荐 因为它是在你搜索的时候又发起了一次新的请求来拿到推荐的内容 它的效率整体也是比较低的。
GET /your_index/your_type/_search query : { # 前缀匹配 关键字 match_phrase_prefix : { message : { # 比如你搜索关注白日梦 经过分词器处理后会得到最后一个词是 “白日梦” # 然后他会拿着白日梦再发起一次搜索 于是你就可能搜到下面的内容 # “关注白日梦的微信公众号” # ”关注白日梦的圈子“ query : 关注白日梦 , # 指定前缀最多匹配多少个term 超过这个数量就不在倒排索引中检索了 提升性能 max_expansions : 10, # 提高召回率 使用slop调整term persition 贡献得分 slop :10 }
25、Function Score Query
Function Score Query 实际上是一种让用户可以自定义实现一种对doc得分进行增强的手段。比如 用户可以自定义一个function_secore 函数 然后指定将这个field的值和ES计算出来的分数相乘 作为doc的最终得分。
# Case1 GET /your_index/your_type/_search query : { function_score : { # 正常写一个query query : { match : { query : es # 自定义增强策略 “field_value_factor”:{ # 对检索出的doc的最终得分都要multiply上star字段的值 field : star , boost_mode : multiply , # 限制最大的得分不能超过maxboost指定的值。 maxboost :3 # Case2 GET /your_index/your_type/_search query : { function_score : { query : { match : { query : es “field_value_factor”:{ # 对检索出的doc的最终得分都要multiply上star字段的值 # 这时有个问题 假如说star字段的值为0 那最终结果岂不是都为0 field : star , # 所以考虑使用modifier优化一下 # newScore oldScore log(1 star) modifier : log1p , boost_mode : multiply , maxboost :3 # Case3 GET /your_index/your_type/_search query : { function_score : { query : { match : { query : es “field_value_factor”:{ field : star , modifier : log1p , # 使用factor将star字段对权重的影响降低成1/10 # newScore oldScore log( 1 star*factor ) factor :0.1 boost_mode : multiply , maxboost :3 # 补充boost_mode有哪些中选项 multiply、sum、min、max、replace
26、Fuzzy Query 模糊查询会提供容错的处理
GET /your_index/your_type/_search # Fuzzy Query 模糊查询会提供容错的处理 query : { fuzzy : { user : { value : 白日梦 , boost : 1.0, # 最大的纠错次数 一般设为之AUTO fuzziness : 2, # 不会被“模糊化”的初始字符数。这有助于减少必须检查的术语的数量。默认值为0。 prefix_length : 0, # 模糊查询将扩展到的最大项数。默认值为50 max_expansions : 100 # 是否支持模糊变换(ab→ba)。默认的是false transpositions:true }
27、解读一个实用的案例
GET /your_index/your_type/_search query : { # 比如你的查询比较复杂 涉及到很多的子查询 那你可以考虑通过bool查询包裹这些子查询 # 每一个子查询都会计算出这个doc针对于它这种查询得到的相关性得分。 # 最终由bool查询将这些得分合并为一个最终的得分 bool : { # 必须匹配到XXX 并且会得出相关性得分 # address中必须包含mill must : [ { match : { address : mill # 在满足must的基础上 should条件不满足也可以 但是如果也匹配上了 相关性得分会增加 # 如果没有must的话 should中的条件必须满足一个 should : [ { match : { address : lane } } must_not : [ # 一定不包含谁 { match : { address : mill } }, # filter中的表达式仅仅对数据进行过滤,但是不会影响搜索结果的相关度得分。 # 所以你如果不希望添加的过滤条件影响最终的doc排序的话 可以将条件放在filter中。 # query是会计算doc的相关度得分的 得分越高 越靠前。 filter : { range : { # 按照范围过滤 balance : { # 指定过滤的字段 gte : 20000s # 高于20000 lte : 30000 # 低于30000 }
默认的排序规则是按照_score降序排序 但像上面说的那样 如果全部都是filter的话它就不会计算得分 也就是说所有的得分全是1 这时候就需要定制排序规则 定义的语法我在上面写了
28、查询名称中包含“白日梦”的doc 并且按照star排序
高亮、排序、分页以及_source 指定需要的字段都可以进一步作用在query的结果上。
# ES默认的排序规则是按照 _score 字段降序排序的 # 但是ES允许你像下面这样定制排序规则 GET /your_index/your_type/_search query : { match : { name : 白日 梦 } # 指定排序条件 sort :[ # 指定排序字段为 star { star : desc } }
29、分页查询
如 从第一条doc开启查 查10条。 如果你不使用from、to搜索的话 默认就搜索前10条
GET /your_index/your_type/_search query : { match_all : {} }, from : 0, # 0 是第一个doc size : 10 # 还可以像这样发起分页请求 GET /your_index/your_type/_search?size 10 GET /your_index/your_type/_search?size 10 from 20 # deep paging 问题 比如系统中只有3个primary shard 1个replica shard 共有6W条数据。 用户希望查询第1000页 每页10条数据。也就是1000*10 10001 10010 条数据 假如说用户将这个分页请求会打向ES集群中的replica shard 接下来会发生什么 接收到请求的shard 我们称它为coordinate node 协调节点 它会将请求转发到三个primary 每个primary shard都会取出它们的第1 10010条数据id 返回给coordinate node 也就是说coordinate node总共会接收到30030个id 然后coordinate node再拿着这些id发起mget请求获取数据 对获取到的结果30030排序处理 最后取相关性得分最高的10条返回给用户。 所以当分页过深的时候是非常消耗内存、网络带宽、CPU的。
30、指定要查询出来的doc的某几个字段。如下
# 假设白日梦对应的json长下面这样 name : 白日梦 , “address”: beijing , gender : man # 然后我只想检索出name字段 其他的不想知道 可以像下面这样通过_sorce限制 GET /your_index/your_type/_search query : { match_all : {} }, # ES会返回全文JSON 通过_source可以指定返回的字段 _source : [ name ], }
31、filter过滤 查询name中包含白日梦 且star大于100的doc。
GET /your_index/your_type/_search query : { # 可以使用bool封装包括多个查询条件 “bool :{ must :{ match : { name : 白日 梦 }} # 指定按照star的范围进行filter filter :{ # range既能放在query中 也能放在filter中。 # 如果放在filter中 range过滤的动作不会影响最终的得分。 # 但是放在query中 range动作会影响最终的得分。 range :{ “star”:{ gt :100} # 拓展 # 关于range还可以像这样过滤时间 range :{ # 指定birthday范围为最近一个月的doc birthday :{ gt : 2021-01-20||-30d # 或者使用now语法 # 指定birthday范围为最近一个月的doc birthday :{ gt : now-30d }
32、指定对返回的doc中指定字段中的指定单词高亮显示。
GET /your_index/your_type/_search query : { match : { name : 白日 梦 } highlight :{ # 高亮显示 fields :{ # 指定高亮的字段为 firstname firstname :{} # 最终得到的返回值类似下面这样 ... hits : { total : 1000,# 1000个 max_score : null, hits : [ { _index : bank , _type : _doc , _id : 0 , sort : [0], _score : 0.777777, _source : { account_number :0, balance :16623, firstname : 我是白 , lastname : 日梦 , state : CO } highlight :{ firstname :[ 我是 em 白 /em ...
参考 https://www.elastic.co/guide/en/elasticsearch/reference/6.2/query-dsl.html
Elasticsearch全观测技术解析与应用(构建日志、指标、APM统一观测平台) 立即下载
相关文章
- 极兔一面:10亿级ES海量搜索狂飙10倍,该怎么办?
- new QDM 前后端开发总结(net6+vue+mysql+redis+mq+mongodb+ES+docker)
- 当es使用script脚本查询聚合等操作遇到空字段报错问题解决方案
- 淘东电商项目(38) -Docker下安装ES&Kibana(一次填完所有的坑)
- 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》一6.4 点法向量和面法向量
- 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》一6.5 光照的每顶点计算与每片元计算
- 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》一6.6 本章小结
- 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》——6.6节本章小结
- 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》——导读
- 《OpenGL ES应用开发实践指南:Android卷》——第3章 编译着色器及在屏幕上绘图
- 《OpenGL ES应用开发实践指南:Android卷》—— 3.1 加载着色器
- ES 自动恢复分片的时候不恢复了是磁盘超过了85%,然后不恢复了 ES可以配置多个数据目录
- 【OpenGL ES】MVP矩阵变换
- ELK之ES-Logstash-Kibana互联