Hi!大家久等了!时隔10天,白日梦的Elasticsearch笔记进阶篇终于甘完了!本次更新依然是干货满满!
下面会和大家分享 32种查询方法、15中聚合方式、7种优化后的查询技巧。欢迎大家转发支持!
如果对ES中的各种概念不太清楚可以去看上一篇文章,白日梦的ES笔记-基础篇,并且有些概念不理解并不会影响你看懂本文中为大家介绍的各种查询方式。
下一篇(白日梦的ES系列笔记第三篇)文章会跟大家一起杀回到基础部分,系统的做一次概念上的扫盲!
最后一篇(ES系列笔记第四篇)以编程语言实战为主,不出意外的话会以视频的方式和大家见面。
欢迎关注白日梦!第一时间追更新!
好消息!!!如果你嫌安装ES麻烦,想使用现成的ES学习,可以免费白嫖白日梦的搭建在公网上的ES实例(有效期还有340多天,预计到2022年初才过期哦)。关注此公号后台回复:白嫖 可得到账号密码。
Notice!!!我不能保证它一定是安全可用哦,毕竟IP直接暴露在公网上是极有可能被黑的。如果你发现服务不可用,可以跟我说一下。我提前做好了镜像,可快速将系统回复如初。(为了安全,我也会不定期更新IP、账号密码)所以大家拿它用来学习还行,不要往上面放重要的数据哈!
关注白日梦(一个专注于技术的百度后端研发)后台回复:白嫖 ,即可领取账号密码。
关注白日梦(一个专注于技术的百度后端研发)后台回复:白嫖 ,即可领取账号密码。
关注白日梦(一个专注于技术的百度后端研发)后台回复:白嫖 ,即可领取账号密码。
点击链接阅读原文:可以找到我公众号的二维码。
另外我也推荐大家阅读原文,json的格式会好看很多!
search api也是我们最需要了解和掌握的APi。因为绝大部分时间你使用ES就是为了检索嘛,所以下面一起看一下ES有哪些检索API,当然最终的目的是大家有拥有选择出一种适合自己业务的检索方式的能力。
我又来吹牛了!
如果你不学白日梦跟你介绍的这些查询方式、技巧。我敢说你八成不懂别人用Java或者Golang写出来的代码。
相反如果你看懂了下面的几十个Case后,我敢说你自己可以分分钟独立的用熟悉的编程语言写出对应的查询代码!
所谓的query string search其实就是ES为我们提供的一种检索方式。下面这行请求就是典型的通过 query string search的方式进行检索。
其实这种检索方式很少用。直观上看 query string search 这种检索方式的特点就是它的请求参数全部写在URI中。
GET /your_index/your_type/_search?q=*&sort=account_number:asc&pretty
解读一下上面的 query string search: q=*
,表示匹配index=bank的下的所有doc,sort=account_number:asc
表示告诉ES,结果按照account_number字段升序排序,pretty
是告诉ES,返回一个漂亮的json格式的数据。
上面的q还可以写成下面这样:
GET /your_index/your_type/_search?q=自定义field:期望的值
GET /your_index/your_type/_search?q=+自定义field:期望的值
GET /your_index/your_type/_search?q=-自定义field:期望的值
解读ES返回的响应如下(包括后面的query dsl的几十种查询案例的返回值也长这样,并且下面不再重复分析这个返回值都有啥字段了,所以推荐你好好看下这个返回值再去浏览本文的重头戏:query dsl 和 查询优化技巧哈):
{
"took" : 63,// 耗费的时间
// 是否超时了,默认情况下不存在time_out,比如你的搜索耗时1分钟,它就等1分钟,但是不超时
// 在发送搜索请求时可以指定超时时间
// 比如你指定了10ms超时,它就会把这10ms内获得的数据返回给你
"timed_out" : false,
"_shards" : {
// 你的搜索请求打到了几个shard上面去。
// Primary Shard可以承接读、写流量。Replica Shard会承接读流量。
// 因为我是默认配置,有五个primary shard。
// 所以它的搜索请求会被打到5个分片上去,并且都成功了
"total" : 5,
"successful" : 5,
"skipped" : 0,// 跳过了0个
"failed" : 0 // 失败了0个
},
"hits" : {
//命中的情况
"total" : 1000,// 命中率 1000个
// _score 全文检索时使用,这个相关性得分越高,说明doc和检索的内容的越相关、越匹配
// max_score就是最大的 _score
"max_score" : null,
// 默认查询前10条,直接返回每个doc的完整数据
"hits" : [ {
"_index" : "bank",// 索引
"_type" : "_doc",// type
"_id" : "0",// id
"sort": [0],
"_score" : null,// 相关性得分
// _source里面存放的是doc的具体数据
"_source" : {
"account_number":0,
"balance":16623,
"firstname":"Bradshaw",
"lastname":"Mckenzie",
"age":29,
"gender":"F",
"address":"244 Columbus Place",
"employer":"Euron",
"email":"[email protected]",
"city":"Hobucken",
"state":"CO"}
},
{
"_index" : "bank",
"_type" : "_doc",
"_id" : "1",
"sort": [1],
"_score" : null,
"_source" : {
"account_number":1,
"balance":39225,
"firstname":"Amber",
"lastname":"Duke",
"age":32,
"gender":"M",
"address":"880 Holmes Lane",
"employer":"Pyrami",
"email":"[email protected]",
"city":"Brogan",
"state":"IL"}
}, ...
]
}
}
指定超时时间: GET /_search?timeout=10ms
在进行优化时,可以考虑使用timeout, 比如: 正常来说我们可以在10s内获取2000条数据,但是指定了timeout,发生超时后我们可以获取10ms中获取到的 100条数据。
dsl 全程 domain specified language
不论是query string search 还是这小节的query specified language它们本质上都是在发送Resutful类型的网络请求。相对于 query string search 的将所有的请求参数都写在URI中,query dsl 一般长下面这样:
GET /yourIndex/yourType/_search
{
// 很多请求参数
}
说的直白一点,query string search 更像是http中的GET请求,因为它没有请求体。而本小节的query dsl 更像是http 中的POST请求。
下面一起看一下有哪些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": [ {<