白日夢的Elasticsearch實(shí)戰(zhàn)筆記崔赌,ES賬號免費(fèi)借用、32個查詢案例耸别、15個聚合案例健芭、7個查詢優(yōu)化技巧。

一秀姐、導(dǎo)讀

Hi慈迈!大家久等了!時隔10天省有,白日夢的Elasticsearch筆記進(jìn)階篇終于甘完了痒留!本次更新依然是干貨滿滿!

image

下面會和大家分享 32種查詢方法蠢沿、15中聚合方式伸头、7種優(yōu)化后的查詢技巧。歡迎大家轉(zhuǎn)發(fā)支持舷蟀!

如果對ES中的各種概念不太清楚可以去看上一篇文章恤磷,白日夢的ES筆記-基礎(chǔ)篇,并且有些概念不理解并不會影響你看懂本文中為大家介紹的各種查詢方式野宜。

下一篇(白日夢的ES系列筆記第三篇)文章會跟大家一起殺回到基礎(chǔ)部分扫步,系統(tǒng)的做一次概念上的掃盲!

最后一篇(ES系列筆記第四篇)以編程語言實(shí)戰(zhàn)為主速缨,不出意外的話會以視頻的方式和大家見面锌妻。

歡迎關(guān)注白日夢!第一時間追更新旬牲!

二仿粹、福利:賬號借用

好消息8橄拧!吭历!如果你嫌安裝ES麻煩堕仔,想使用現(xiàn)成的ES學(xué)習(xí),可以免費(fèi)白嫖白日夢的搭建在公網(wǎng)上的ES實(shí)例(有效期還有340多天晌区,預(yù)計(jì)到2022年初才過期哦)摩骨。關(guān)注此公號后臺回復(fù):白嫖 可得到賬號密碼。

image

Notice@嗜簟D瘴濉!我不能保證它一定是安全可用哦哭懈,畢竟IP直接暴露在公網(wǎng)上是極有可能被黑的灾馒。如果你發(fā)現(xiàn)服務(wù)不可用,可以跟我說一下遣总。我提前做好了鏡像睬罗,可快速將系統(tǒng)回復(fù)如初。(為了安全旭斥,我也會不定期更新IP容达、賬號密碼)所以大家拿它用來學(xué)習(xí)還行,不要往上面放重要的數(shù)據(jù)哈垂券!

關(guān)注白日夢(一個專注于技術(shù)的百度后端研發(fā))后臺回復(fù):白嫖 花盐,即可領(lǐng)取賬號密碼。
關(guān)注白日夢(一個專注于技術(shù)的百度后端研發(fā))后臺回復(fù):白嫖 圆米,即可領(lǐng)取賬號密碼卒暂。
關(guān)注白日夢(一個專注于技術(shù)的百度后端研發(fā))后臺回復(fù):白嫖 ,即可領(lǐng)取賬號密碼娄帖。


點(diǎn)擊鏈接閱讀原文:可以找到我公眾號的二維碼也祠。


另外我也推薦大家閱讀原文,json的格式會好看很多近速!




三诈嘿、_search api 搜索api

search api也是我們最需要了解和掌握的APi。因?yàn)榻^大部分時間你使用ES就是為了檢索嘛削葱,所以下面一起看一下ES有哪些檢索API奖亚,當(dāng)然最終的目的是大家有擁有選擇出一種適合自己業(yè)務(wù)的檢索方式的能力。

我又來吹牛了析砸!

image

如果你不學(xué)白日夢跟你介紹的這些查詢方式昔字、技巧。我敢說你八成不懂別人用Java或者Golang寫出來的代碼。

相反如果你看懂了下面的幾十個Case后作郭,我敢說你自己可以分分鐘獨(dú)立的用熟悉的編程語言寫出對應(yīng)的查詢代碼陨囊!




3.1、什么是query string search夹攒?

所謂的query string search其實(shí)就是ES為我們提供的一種檢索方式蜘醋。下面這行請求就是典型的通過 query string search的方式進(jìn)行檢索。

其實(shí)這種檢索方式很少用咏尝。直觀上看 query string search 這種檢索方式的特點(diǎn)就是它的請求參數(shù)全部寫在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胎食,結(jié)果按照account_number字段升序排序允懂,pretty是告訴ES斥季,返回一個漂亮的json格式的數(shù)據(jù)。

上面的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返回的響應(yīng)如下(包括后面的query dsl的幾十種查詢案例的返回值也長這樣累驮,并且下面不再重復(fù)分析這個返回值都有啥字段了,所以推薦你好好看下這個返回值再去瀏覽本文的重頭戲:query dsl 和 查詢優(yōu)化技巧哈):

{
  "took" : 63,// 耗費(fèi)的時間
  // 是否超時了舵揭,默認(rèn)情況下不存在time_out,比如你的搜索耗時1分鐘谤专,它就等1分鐘,但是不超時
  // 在發(fā)送搜索請求時可以指定超時時間
  // 比如你指定了10ms超時午绳,它就會把這10ms內(nèi)獲得的數(shù)據(jù)返回給你
  "timed_out" : false,
  "_shards" : { // 你的搜索請求打到了幾個shard上面去置侍。
    // Primary Shard可以承接讀、寫流量拦焚。Replica Shard會承接讀流量蜡坊。
    // 因?yàn)槲沂悄J(rèn)配置,有五個primary shard赎败。
    // 所以它的搜索請求會被打到5個分片上去秕衙,并且都成功了
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,// 跳過了0個
    "failed" : 0 // 失敗了0個
  },
  "hits" : {//命中的情況
    "total" : 1000,// 命中率 1000個
    // _score 全文檢索時使用,這個相關(guān)性得分越高僵刮,說明doc和檢索的內(nèi)容的越相關(guān)据忘、越匹配
    // max_score就是最大的 _score
    "max_score" : null,
    // 默認(rèn)查詢前10條,直接返回每個doc的完整數(shù)據(jù)
    "hits" : [ {   
      "_index" : "bank",// 索引
      "_type" : "_doc",// type
      "_id" : "0",// id 
      "sort": [0],
      "_score" : null,// 相關(guān)性得分
      // _source里面存放的是doc的具體數(shù)據(jù)
      "_source" :       {"account_number":0,
                       "balance":16623,
                       "firstname":"Bradshaw",
                       "lastname":"Mckenzie",
                       "age":29,
                       "gender":"F",
                       "address":"244 Columbus Place",
                       "employer":"Euron",
                       "email":"bradshawmckenzie@euron.com",
                       "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":"amberduke@pyrami.com",
                   "city":"Brogan",
                   "state":"IL"}
    }, ...
    ]
  }
}

指定超時時間: GET /_search?timeout=10ms 在進(jìn)行優(yōu)化時搞糕,可以考慮使用timeout勇吊, 比如: 正常來說我們可以在10s內(nèi)獲取2000條數(shù)據(jù),但是指定了timeout窍仰,發(fā)生超時后我們可以獲取10ms中獲取到的 100條數(shù)據(jù)汉规。




3.2、什么是query dsl驹吮?

dsl 全程 domain specified language

不論是query string search 還是這小節(jié)的query specified language它們本質(zhì)上都是在發(fā)送Resutful類型的網(wǎng)絡(luò)請求针史。相對于 query string search 的將所有的請求參數(shù)都寫在URI中晶伦,query dsl 一般長下面這樣:

GET /yourIndex/yourType/_search
{
  // 很多請求參數(shù)
}

說的直白一點(diǎn),query string search 更像是http中的GET請求悟民,因?yàn)樗鼪]有請求體坝辫。而本小節(jié)的query dsl 更像是http 中的POST請求。




3.3射亏、干貨近忙!32個查詢案例!

下面一起看一下有哪些query dsl的使用方式智润。(查詢的返回值和上面我們一起看的那個是一樣的及舍,所以下面的重點(diǎn)是怎么查,而不是怎么看返回值哈)

1窟绷、查詢指定index下的全部doc

# _search是關(guān)鍵字锯玛,下文基本每個查詢都會有它,不再贅述了哈
GET /your_index/your_type/_search
{
  "query": { "match_all": {} }
}

2兼蜈、針對name字段進(jìn)行全文檢索(match查詢)

ES會將用戶將輸入的字符串通過分詞器拆解開攘残,然后去倒排索引中掃描匹配(下一篇文章白日夢的筆記會重新殺回ES涉及的核心概念,包括這個倒排索引)为狸。在倒排索引中哪怕匹配上了一個也會將結(jié)果返回歼郭。

GET /yourIndex/yourType/_search
{
   "query": { 
     # match表示全文檢索,所以白日夢會被分詞成 白日辐棒、夢病曾、白日夢
     # 也就是說當(dāng)前的match會匹配出name中有“白日” 或者“夢” 或者“白日夢”的doc
     "match": {
       "name":"白日夢"
     } 
   }
}
# 實(shí)際上,match query底層會被轉(zhuǎn)換成下面的格式進(jìn)行檢索
#
# {
#    "bool":{
#        "should":[
#         {"term":{"title":"白日"}},
#                   {"term":{"title":"白日夢"}},
#         {"term":{"title":"夢"}}
#     ]
#  }
# }
#

3漾根、全文檢索:手動控制全文檢索的精度

GET /your_index/your_type/_search
{
   "query": { 
     "match": {
        "name":{
            "query":"bairi meng",
            # and表示泰涂,只有同時出現(xiàn)bairi meng兩個詞的doc才會被命中
            # 如果不加and限制,則bairi和meng之間是或的關(guān)系辐怕,只要出現(xiàn)一個就行
            "operator":"and",  
        }
     }
    }
}
# 添加上operator 操作會被ES轉(zhuǎn)換成下面的格式逼蒙,將上面的should轉(zhuǎn)換成must
#
# {
#    "bool":{
#        "must":[
#         {"term":{"title":"bairi"}},
#         {"term":{"title":"meng"}}
#     ]
#  }
# }

4、去掉全文檢索的長尾

# 去長尾
GET /your_index/your_type/_search
{
   "query": { 
     "match": {
        "name":{
            "query":"歡迎關(guān)注白日夢秘蛇!",
            "operator":"and",  
            # 上面的query可能被分詞成: 歡迎其做、關(guān)注、白日夢赁还、歡迎關(guān)注妖泄、關(guān)注白日夢這五個詞。
            # 默認(rèn)來說只要命中其中的一個詞艘策,那個doc就會被返回蹈胡,所以有長尾現(xiàn)象。
            # 去長尾:控制至少命中3/4個詞的doc才算是真正命中。
            "minimum_should_match":"75%" 
        }
     }
    }
}
# 添加上 minimum_should_match 操作會被ES轉(zhuǎn)換成下面的格式 
#
# {
#    "bool":{
#        "should":[
#         {"term":{"title":"白日"}},
#         {"term":{"title":"夢"}}
#     ],
#       "minimum_should_match":3
#  }
# }
#  

5罚渐、全文檢索:通過boost控制權(quán)重却汉。

如下Case:要求doc的name字段必須包含:“關(guān)注”,于此同時荷并,如果doc的name字段中包含:“白日夢”合砂,則將這個doc的權(quán)重提高為3,如果name字段中包含了“公眾號” 再提高它的權(quán)重2源织。經(jīng)過這樣的處理翩伪,name字段中包含:“關(guān)注白日夢公眾號” 的doc的權(quán)重就最高,它在搜索結(jié)果中的排名就越靠前谈息。

GET /your_index/your_type/_search
{
   "query": { 
     "bool":{
            "must":{
                "match": {
                 "name":{
                        # 默認(rèn)情況下缘屹,所有字段的權(quán)重都是樣的,都是1
                    "query":"關(guān)注",
                    }
                    }
             },
             "should":[
                    {
                    "match": {
                 "name":{
                    "query":"白日夢",
                    # 將name字段的權(quán)重提升成3
                    "boost":3 
                    }
                    }
                    },
                    {
                    "match": {
                 "name":{
                    "query":"公眾號",
                    # 將name字段的權(quán)重提升成3
                    # 默認(rèn)情況下侠仇,所有字段的權(quán)重都是樣的轻姿,都是1
                    "boost":2  
                    }
                    }
                }
            ]
      }
   }
}   

6、稍微復(fù)雜一點(diǎn)的多條件查詢:bool查詢

GET /your_index/your_type/_search
{ 
  "query": {
    # 比如你的查詢比較復(fù)雜逻炊,涉及到很多的子查詢互亮,那你可以考慮通過bool查詢包裹這些子查詢
    # 每一個子查詢都會計(jì)算出這個doc針對于它這種查詢得到的相關(guān)性得分。
    # 最終由bool查詢將這些得分合并為一個最終的得分
    "bool": {
      # 必須匹配到XXX余素, 并且會得出相關(guān)性得分
      # address中必須包含mill 
      "must": [ {"match": { "address": "mill" } }, 
      ],
      # 在滿足must的基礎(chǔ)上胳挎,should條件不滿足也可以,但是如果也匹配上了溺森,相關(guān)性得分會增加
      # 如果沒有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都會貢獻(xiàn)自己的相關(guān)性得分,也就是說doc最終的相關(guān)性得分是通過這多個match貢獻(xiàn)的相關(guān)性得分通過一定的機(jī)制計(jì)算出來的卷要。而且相關(guān)性得分越高,文檔在搜索結(jié)果中就越靠前。

這時块饺,如果你不希望讓doc的最終得分是通過綜合所有的match計(jì)算得出的哥谷,可以使用dis_max查詢。它會取所有match中得分最高的match當(dāng)作doc的最終得分瓶堕。

GET /your_index/your_type/_search
{
   "query": { 
     # 這種用法不容忽略
     # 直接取下面多個query中得分最高的query當(dāng)成最終得分
     "dis_max": {
        "queries":[
           {"match":{"name":"白日夢"}},
           {"match":{"content":"關(guān)注白日夢隘道!"}}
        ]
     }
   }
}

9、基于 tie_breaker 優(yōu)化dis_max

上面的Case中有提到這個dis_max查詢,這個dis_max也是實(shí)現(xiàn)best field的關(guān)鍵谭梗,即:它會取所有match中得分最高的match當(dāng)作doc的最終得分忘晤。

而這個例子中的tie_breaker會重新讓dis_max考慮到其他field的得分影響,比如下面的0.4激捏,表示最終的doc得分會考慮其他match的影響设塔,但是它的影響會被弱化成原來的0.4。

GET /your_index/your_type/_search
{   
    # 基于 tie_breaker 優(yōu)化dis_max
    # tie_breaker可以使dis_max考慮其它field的得分影響
    "query": { 
     # 直接取下面多個query中得分最高的query當(dāng)成最終得分
     # 這也是best field策略
     "dis_max": { 
        "queries":[
           {"match":{"name":"關(guān)注"}},
           {"match":{"content":"白日夢"}}
        ],
        "tie_breaker":0.4
     }
    }
}   

10远舅、同時在你指定的多個字段中進(jìn)行檢索: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 優(yōu)化dis_max
    # tie_breaker可以使dis_max考慮其它field的得分影響
    "query": { 
     # 直接取下面多個query中得分最高的query當(dāng)成最終得分
     # 這也是best field策略
     "dis_max": { 
        "queries":[
           {"match":{"name":"關(guān)注"}},
           {"match":{"content":"白日夢"}}
        ],
        "tie_breaker":0.4
     }
    }
} 

# 使用multi_match query簡化寫法如下:
GET /your_index/your_type/_search
{    
    "query": { 
       "multi_match":{
           "query":"關(guān)注 白日夢",
                      # 指定檢索的策略 best_fields(因?yàn)閐is_max就是best field策略)
           "type":"best_fields",
                    # content^2 表示增加權(quán)重钞护,相當(dāng)于:boost2
           "fields":["name","content^2"],
                     "tie_breaker":0.4,
                     "minimum_should_match":3
       }
    }
}

12、most field策略和上面說的best field策略是不同的爆办,因?yàn)閎est field策略說的是:優(yōu)先返回某個field匹配到更多關(guān)鍵字的doc难咕。

優(yōu)先返回有更多的field匹配到你給定的關(guān)鍵字的doc。而不是優(yōu)先返回某個field完全匹配你給定關(guān)鍵字的doc

另外most_fields不支持使用minimum_should_match去長尾距辆。

GET /your_index/your_type/_search
{    
    # most_fields策略余佃、優(yōu)先返回命中更多關(guān)鍵詞的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中出現(xiàn)
            # cross_fields 要求java:必須在title或者在content中出現(xiàn)
           "type":"cross_fields",
           "fields":["title","content"]
       }
    }
}

14、查詢空

GET /your_index/your_type/_search
{   
  "query": { 
    "match_none": {}
  }
}

15诸蚕、精確匹配

# 使用trem指定單個字段進(jìn)行精確匹配
GET /your_index/your_type/_search
{   
  # 精確匹配name字段為白日夢的doc
  "query": { 
    "constant_score":{
            "filter":{
                    "term": {
                    "name":"白日夢"
                 } 
            }
        }
    } 
}

# 使用terms指定在多個字段中進(jìn)行精確匹配
# 下面的例子相當(dāng)于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來保證的
  # 精準(zhǔn)度很高漠魏,但是召回率低
  "query": {  
                # 只有name字段中包含了完整的 白日夢 這個doc才算命中
              # 不能是單個 ”白日“倔矾,也不能是單個的 “夢”,也不能是“白日xxx夢”
              # 要求 短語相連柱锹,且順序也不能變
         "match_phrase": { 
             "name": "白日夢"
                    }
        }
}

17哪自、提高短語檢索的召回率

如果使用match_phase進(jìn)行短語檢索,本質(zhì)上就是要求doc中的字段值和給定的值完全相同禁熏,即使是順序不同也不行壤巷。但是為了提高召回率如你又想容忍短語匹配可以存在一定的誤差,比如你希望搜索 “i love world” 時瞧毙,能夠搜索出''world love i"

這時可以通過slop來實(shí)現(xiàn)這個功能隙笆,slop可以幫你讓指定短語中的詞最多經(jīng)過slop次移動后如果能匹配某個doc锌蓄,也把這個doc當(dāng)作結(jié)果返回給用戶。

GET /your_index/your_type/_search
{    
   # 短語檢索
   "query": {
           # 指定了slop就不再要求搜索term之間必須相鄰撑柔,而是可以最多間隔slop距離瘸爽。
         # 在指定了slop參數(shù)的情況下,離關(guān)鍵詞越近铅忿,移動的次數(shù)越少剪决, relevance score 越高。
         # match_phrase +  slop 和 proximity match 近似匹配作用類似檀训。
         # 平衡精準(zhǔn)度和召回率柑潦。
         "match_phrase": { 
             "address": "mill lane",
                         # 指定搜索文本中的幾個term經(jīng)過幾次移動后可以匹配到一個doc
             "slop":2
          } 
  }
}

18、混合使用match和match_phrase 平衡精準(zhǔn)度和召回率

GET /your_index/your_type/_search
{    
   # 混合使用match和match_phrase 平衡精準(zhǔn)度和召回率
   "query": { 
      "bool": {  
        "must":  {
            # 全文檢索雖然可以匹配到大量的文檔峻凫,但是它不能控制詞條之間的距離
            # 可能i love world在doc1中距離很近渗鬼,但是它卻被ES排在結(jié)果集的后面
            # 它的性能比match_phrase和proximity高
                "match": {
                "title": "i love world" 
            } 
             },
        "should": {
            # 因?yàn)閟lop有個特性:詞條之間間隔的越近,移動的次數(shù)越少 最終的得分就越高
            # 于是可以借助match_phrase+slop感知term position的功能
            # 實(shí)現(xiàn)為距離相近的doc貢獻(xiàn)分?jǐn)?shù)荧琼,讓它們靠前排列
            "match_phrase":{
                "title":{
                    "query":"i love world",
                    "slop":15
                }
            }
        }
    }
}

19譬胎、使用rescore_query重打分。提高精準(zhǔn)度和召回率命锄。

GET /your_index/your_type/_search
{    
   # 重打分機(jī)制
   "query": { 
       "match":{
           "title":{
               "query":"i love world",
               "minimum_should_match":"50%"
           }
       },
       # 對全文檢索的結(jié)果進(jìn)行重新打分
       "rescore":{
             # 對全文檢索的前50條進(jìn)行重新打分
           "window_size":50堰乔,  
           "query": { 
               # 關(guān)鍵字
               "rescore_query":{ 
                      # match_phrase + slop 感知 term persition,貢獻(xiàn)分?jǐn)?shù)
                    "match_phrase":{ 
                       "title":{
                           "query":"i love world",
                           "slop":50
                     }
                }
          }
       } 
   }
}

20脐恩、前綴匹配:搜索 user字段以"白日夢"開頭的 doc

GET /your_index/your_type/_search
{    
  # 前綴匹配镐侯,相對于全文檢索,前綴匹配是不會對前綴進(jìn)行分詞的驶冒。
  # 而且每次匹配都會掃描整個倒排索引苟翻,直到掃描完一遍才會停下來
  # 前綴搜索不會計(jì)算相關(guān)性得分所有的doc的得分都是1
  # 前綴越短能匹配到的doc就越多,性能越不好
  "query": { 
    "prefix" : { "user" : "白日夢" }
  }
}

21骗污、前綴搜索 + 添加權(quán)重

GET /your_index/your_type/_search
{    
  # 前綴搜索 + 添加權(quán)重
  "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,最終實(shí)現(xiàn)的效果類似于百度搜索拍鲤,當(dāng)用戶輸入一個詞條后贴谎,將其它符合條件的詞條的選項(xiàng)推送出來。

match_phrase_prefix和match_phrase相似季稳,但是區(qū)別是它會將最后一個term當(dāng)作前綴擅这,發(fā)起一次搜索。因此它也叫search time 搜索推薦景鼠,因?yàn)樗窃谀闼阉鞯臅r候又發(fā)起了一次新的請求來拿到推薦的內(nèi)容仲翎,它的效率整體也是比較低的痹扇。

GET /your_index/your_type/_search
{    
   "query": {
      # 前綴匹配(關(guān)鍵字)
      "match_phrase_prefix" : {
        "message" : {
                            # 比如你搜索關(guān)注白日夢,經(jīng)過分詞器處理后會得到最后一個詞是:“白日夢”
                          # 然后他會拿著白日夢再發(fā)起一次搜索溯香,于是你就可能搜到下面的內(nèi)容:
                # “關(guān)注白日夢的微信公眾號”
                            # ”關(guān)注白日夢的圈子“
                "query" : "關(guān)注白日夢",
                # 指定前綴最多匹配多少個term鲫构,超過這個數(shù)量就不在倒排索引中檢索了,提升性能
                "max_expansions" : 10,
                # 提高召回率玫坛,使用slop調(diào)整term persition结笨,貢獻(xiàn)得分
                "slop":10
            }
       } 
  }
}

25、Function Score Query

Function Score Query 實(shí)際上是一種讓用戶可以自定義實(shí)現(xiàn)一種對doc得分進(jìn)行增強(qiáng)的手段湿镀。比如:用戶可以自定義一個function_secore 函數(shù)炕吸,然后指定將這個field的值和ES計(jì)算出來的分?jǐn)?shù)相乘,作為doc的最終得分勉痴。

# Case1
GET /your_index/your_type/_search
{    
  "query": {
        "function_score": {
            # 正常寫一個query
            "query": { 
                "match": {
                    "query":"es"
                } 
                    },
                  # 自定義增強(qiáng)策略
                    “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蒸矛,那最終結(jié)果豈不是都為0瀑罗?
              "field":"star",
              # 所以考慮使用modifier優(yōu)化一下
              # 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字段對權(quán)重的影響降低成1/10
              # newScore = oldScore + log( 1 + star*factor )
                        "factor":0.1
            }
            "boost_mode":"multiply",
                        "maxboost":3
        }
    }
}

# 補(bǔ)充boost_mode有哪些中選項(xiàng)
multiply、sum莉钙、min廓脆、max、replace

26磁玉、Fuzzy Query 模糊查詢會提供容錯的處理

GET /your_index/your_type/_search
{    
   # Fuzzy Query 模糊查詢會提供容錯的處理
   "query": {
        "fuzzy" : {
            "user" : {
                "value": "白日夢",
                "boost": 1.0,
                # 最大的糾錯次數(shù)停忿,一般設(shè)為之AUTO
                "fuzziness": 2,
                # 不會被“模糊化”的初始字符數(shù)。這有助于減少必須檢查的術(shù)語的數(shù)量蚊伞。默認(rèn)值為0席赂。
                "prefix_length": 0,
                # 模糊查詢將擴(kuò)展到的最大項(xiàng)數(shù)。默認(rèn)值為50
                "max_expansions": 100 
                # 是否支持模糊變換(ab→ba)时迫。默認(rèn)的是false
                transpositions:true 
            }
        }
    }
}

27颅停、解讀一個實(shí)用的案例

GET /your_index/your_type/_search
{ 
  "query": {
    # 比如你的查詢比較復(fù)雜,涉及到很多的子查詢掠拳,那你可以考慮通過bool查詢包裹這些子查詢
    # 每一個子查詢都會計(jì)算出這個doc針對于它這種查詢得到的相關(guān)性得分癞揉。
    # 最終由bool查詢將這些得分合并為一個最終的得分
    "bool": {
      # 必須匹配到XXX, 并且會得出相關(guān)性得分
      # address中必須包含mill 
      "must": [ {
            "match": {
          "address": "mill" 
           } 
        }, 
      ],
      # 在滿足must的基礎(chǔ)上溺欧,should條件不滿足也可以喊熟,但是如果也匹配上了,相關(guān)性得分會增加
      # 如果沒有must的話姐刁,should中的條件必須滿足一個
      "should": [
        { "match": { "address": "lane" } }
      ],
      "must_not": [ # 一定不包含誰
        { "match": { "address": "mill" } },
      ],
            # filter中的表達(dá)式僅僅對數(shù)據(jù)進(jìn)行過濾,但是不會影響搜索結(jié)果的相關(guān)度得分芥牌。
            # 所以你如果不希望添加的過濾條件影響最終的doc排序的話,可以將條件放在filter中聂使。
            # query是會計(jì)算doc的相關(guān)度得分的壁拉,得分越高谬俄,越靠前。
      "filter": { 
        "range": { # 按照范圍過濾
          "balance": { # 指定過濾的字段
            "gte": 20000s # 高于20000
            "lte": 30000  # 低于30000
          }
        }
      }
    }
  }

默認(rèn)的排序規(guī)則是按照_score降序排序弃理,但像上面說的那樣溃论,如果全部都是filter的話它就不會計(jì)算得分,也就是說所有的得分全是1案铺,這時候就需要定制排序規(guī)則蔬芥,定義的語法我在上面寫了

28、查詢名稱中包含“白日夢”的doc控汉,并且按照star排序

高亮笔诵、排序、分頁以及_source 指定需要的字段都可以進(jìn)一步作用在query的結(jié)果上姑子。

# ES默認(rèn)的排序規(guī)則是按照 _score 字段降序排序的

# 但是ES允許你像下面這樣定制排序規(guī)則
GET /your_index/your_type/_search
{
   "query": { 
     "match": {"name":"白日 夢"}
   },
  # 指定排序條件
  "sort":[
    # 指定排序字段為 star
    {"star":"desc"}
  ]
}   

29乎婿、分頁查詢

如:從第一條doc開啟查,查10條街佑。(如果你不使用from谢翎、to搜索的話,默認(rèn)就搜索前10條)

GET /your_index/your_type/_search
{
   "query": { "match_all": {} },
      "from": 0, # 0:是第一個doc
    "size": 10
}   

# 還可以像這樣發(fā)起分頁請求
GET /your_index/your_type/_search?size=10
GET /your_index/your_type/_search?size=10&from=20

# deep paging 問題
比如系統(tǒng)中只有3個primary shard沐旨,1個replica shard森逮,共有6W條數(shù)據(jù)。
用戶希望查詢第1000頁磁携,每頁10條數(shù)據(jù)褒侧。也就是1000*10 = 10001 ~ 10010 條數(shù)據(jù)
假如說用戶將這個分頁請求會打向ES集群中的replica shard,接下來會發(fā)生什么谊迄?
回答:
接收到請求的shard 我們稱它為coordinate node(協(xié)調(diào)節(jié)點(diǎn))闷供,它會將請求轉(zhuǎn)發(fā)到三個primary,
每個primary shard都會取出它們的第1~10010條數(shù)據(jù)id统诺,返回給coordinate node歪脏,
也就是說coordinate node總共會接收到30030個id,然后coordinate node再拿著這些id發(fā)起mget請求獲取數(shù)據(jù)
對獲取到的結(jié)果30030排序處理粮呢,最后取相關(guān)性得分最高的10條返回給用戶婿失。

所以當(dāng)分頁過深的時候是非常消耗內(nèi)存、網(wǎng)絡(luò)帶寬啄寡、CPU的豪硅。

30、指定要查詢出來的doc的某幾個字段这难。如下:

# 假設(shè)白日夢對應(yīng)的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的范圍進(jìn)行filter
              "filter":{
            # range既能放在query中,也能放在filter中剪个。
            # 如果放在filter中秧骑,range過濾的動作不會影響最終的得分。
            # 但是放在query中扣囊,range動作會影響最終的得分乎折。
            "range":{
                            “star”:{"gt":100}
                 }
         }
      }
   }
}  

# 拓展:
# 關(guān)于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




四骂澄、聚合分析




4.1、什么是聚合分析惕虑?

聚合分析有點(diǎn)類似于SQL語句中的那種group by坟冲、where age > 20 and age < 30、這種操作溃蔫。常見的聚合分析就是根據(jù)某一個字段進(jìn)行分組分析健提,要求這個字段是不能被分詞的,如果被聚合的字段被分詞伟叛,按照倒排索引的方式去索引的話私痹,就不得不去掃描整個倒排索引(才可能將被聚合的字段找全,效率很低)痪伦。

聚合分析是基于doc value的數(shù)據(jù)結(jié)果集進(jìn)行操作的侄榴,這個doc value 其實(shí)就是正排索引(現(xiàn)在了解就好,下一篇文章統(tǒng)一掃盲)网沾,

關(guān)于聚合分析有三個重要的概念:

  • bucket

    特別是你去使用一下java癞蚕、golang中的es相關(guān)的api,就會看到這個bucket關(guān)鍵字辉哥,bucket就是聚合操作得到的結(jié)果集桦山。

  • metric

    metric就是對bucket進(jìn)行分析,比如取最大值醋旦、最小值恒水、平均值。

  • 下鉆

    下鉆就是在現(xiàn)有的分好組的bucket繼續(xù)分組饲齐,比如可以先按性別分組钉凌、下鉆再按年齡分組。




4.2捂人、干貨御雕!15個聚合分析案例

1矢沿、比如我們公司人很多,其中不泛有很多重名的人酸纲,現(xiàn)在我的需求是:我想知道我們公司中有多個人叫tom捣鲸、多少個人叫jerry,也就是說闽坡,我想知道:重名的人分別有多少個栽惶。于是我們需要像下面這樣根據(jù)名字聚合。

聚合的結(jié)果中天然存在一個metric疾嗅,它就是當(dāng)前bucket的count外厂,也就是我們想要的結(jié)果:

GET /your_index/your_type/_search
{   
  # 表示只要聚合的結(jié)果,而不要參與聚合的原始數(shù)據(jù)
  “size”:0,
  # 使用聚合時宪迟,天然存在一個metric酣衷,就是當(dāng)前bucket的count
  "aggs": {
    "group_by_name": { # 自定義的名字
      "term": {
        "field": "name" # 指定聚合的字段, 意思是 group by name
      }
    }
  }
} 

GET /your_index/your_type/_search
{   
  “size”:0,
   # 使用聚合時次泽,天然存在一個metric穿仪,就是當(dāng)前bucket的count
  "aggs": {
    "group_by_xxx": { # 自定義的名字
     # 除了使用term還可以使用terms
     # trems允許你指定多個字段
     "terms": {
         # 指定聚合的字段, 意思是 group by v1意荤、v2啊片、v3
        "field": {"value1","value2","value3"} 
      }
    }
  }
} 

2、先搜索玖像,再對搜索結(jié)果聚合紫谷。比如我想知道在所有的男生中的重名情況

GET /your_index/your_type/_search
{   
  # 先查詢
  “query”:{
        "term":{
        "gender":"man"
      }
  },
   # 再聚合
  "aggs": {
    "group_by_name": { 
      "term": {
        "field": "name" # 指定聚合的字段, 意思是 group by name
      }
    }
  }
} 

3捐寥、我想把重名的人分成一組笤昨,然后我想了解每組人的平均年齡∥湛遥可以像下面這樣干

GET /your_index/your_type/_search
{   
  "size":0,
     # 聚合中嵌套聚合瞒窒,意思是先 group by avg age,再 group by field1乡洼。
  "aggs": {
    "group_by_name": {
      "terms": {
        "field": "name"
      },
             # 在上面的name分組的結(jié)果之上再按照age聚合
      "aggs": { 
        "average_age": {
          # 指定聚合函數(shù)為avg
          "avg": {
            "field": "age"
          }
        }
      }
    }
  }
} 

4崇裁、我想了解我們公司不同年齡段:20歲~25歲有多少人、25歲~30歲有多少人束昵、30歲~35歲拔稳、35歲~40歲有多少人,以及每個年齡段有多少女生锹雏,多少男生巴比。

GET /your_index/your_type/_search
{   
   "size":0,
   # 先按照年齡分組,在按照性別分組
   "aggs": {
    "group_by_age": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 20,
            "to": 25
          },{
            "from": 25,
            "to": 30
          },{
            "from": 30,
            "to": 35
          },{
            "from": 35,
            "to": 40
          }
        ]
      },
      "aggs": {
        "group_by_gender": {
          "terms": {
            # gender.keyword一般是ES自動為我們創(chuàng)建的類型
            # keyword類型的field不會分詞、默認(rèn)長度256字符
            # 這里大家初步了解有這個東西轻绞,知道怎么回事就行腰耙,下一篇文章掃盲
            "field": "gender.keyword"
          }
        }
         }
        }
} 

5、我想知道我們公司每個年齡段铲球,每個性別的平均賬戶余額。

GET /your_index/your_type/_search
{       
  "size":0,
   # 先按照年齡分組晰赞,在按照性別分組稼病,再按照平均工資聚合
   # 最終的結(jié)果就得到了每個年齡段,每個性別的平均賬戶余額
   "aggs": {
    "group_by_age": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 20,
            "to": 30
          }
        ]
      },
      "aggs": {
        "group_by_gender": {
          "term": {
            "field": "gender.keyword"
          },
          # 在上一層根據(jù)gender聚合的基礎(chǔ)上再基于avg balance聚合
          "aggs": {
            "average_balance": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
        }
} 

6掖鱼、嵌套聚合然走,并且使用內(nèi)部聚合的結(jié)果集

GET /your_index/your_type/_search
{       
  "size":0,    
   # 嵌套聚合,并且使用內(nèi)部聚合的結(jié)果集
   "aggs": { 
    "group_by_state": {
      "term": {
        "field": "state.keyword",
        "order": {
          # average_balance是下面內(nèi)部聚合的結(jié)果集合戏挡,在此基礎(chǔ)上做desc
          "average_balance": "desc" 
        }
      },
            # 如下的agg會產(chǎn)出多個bucket如:
      # bucket1 => {state=1芍瑞,acg=xxx、min=xxx褐墅、max=xxx拆檬、sum=xxx}
        # bucket2 => {state=2,acg=xxx妥凳、min=xxx竟贯、max=xxx、sum=xxx}
      "aggs": {
        "average_balance": {
          "avg": {  # avg 求平均值  metric
            "field": "balance"
          }
        },
         "min_price": {
          "min": {  # metric 求最小值
            "field": "price"
          }
        },
         "max_price": {
          "max": {  # metric 求最大值
            "field": "price"
          }
        },
         "sum_price": {
          "sum": {  # metric 計(jì)算總和
            "field": "price"
          }
        },
      }
    }
  }
}

8逝钥、除了前面說的按照值分組聚合屑那,比如男、女艘款,還可以使用histogram按區(qū)間聚合分析持际。

GET /your_index/your_type/_search
{
  "size":0,   
  # histogram,類似于terms哗咆,同樣會進(jìn)行bucket分組操作蜘欲。
  # 使用histogram需要執(zhí)行一個field,比如下例中的age岳枷,表示按照age的范圍進(jìn)行分組聚合
  "aggs": { # 聚合中嵌套聚合
      "group_by_price": {
            "histogram": {
                 "field": "age",
                              # interval為10芒填,它會劃分成這樣 0-10  10-20  20-30 ...
                                # 那age為21的記錄就會被分進(jìn)20-30的區(qū)間中
                 "interval":10
             },
       "aggs": { # 聚合中嵌套聚合
            "average_price": {
               "avg": {
                  "field": "price"
               }
            }
        }
     }
  }
}

9、根據(jù)日期進(jìn)行聚合

GET /your_index/your_type/_search
{       
  "size":0, 
  "aggs": {
     "agg_by_time" : { 
            # 關(guān)鍵字
          "date_histogram" : {
                "field" : "age",
                        # 間隔空繁,一個月為一個跨度
                "interval" : "1M",
                "format" : "yyyy-MM-dd",
                        # 即使這個區(qū)間中一條數(shù)據(jù)都沒有殿衰,這個區(qū)間也要返回
                "min_doc_count":0 
                        # 指定區(qū)間
                        “extended_bounds”:{
                            "min":"2021-01-01",
                          "max":"2021-01-01",
                            }
            } 
        }
    }
}

# 補(bǔ)充
"interval":“quarter”按照季度劃分

10、filter aggregate 過濾盛泡、聚合闷祥。

# Case1
# 如下例子:我想先過濾出年齡大于20的人,然后聚合他們的平均工資
GET /your_index/your_type/_search
{
  "size":0,
  "query":{
    "consitant_score":{
      # 這個filter會針對ES中全局的數(shù)據(jù)進(jìn)行filter
      "filter":{
        "range":{"age":{"gte":20}}
      }
    }
  },
  "aggs":{
    "avg_salary":{
      "avg":{
        "field":"salary"
      }
    }
  }
}

# Case2
# bucket filter
POST /sales/_search
{
    "aggs" : {
        # T恤bucket的agg
        "agg_t_shirts" : {
            "filter" : { 
              "term": {
                "type": "t-shirt" 
              }
            },
            "aggs" : {
                "avg_price" : { "avg" : { "field" : "price" } }
            }
        },
            # 毛衣bucket的agg
      "agg_sweater" : {
            "filter" : { 
              "term": {
                "type": "sweater" 
              }
            },
            "aggs" : {
                "avg_price" : { "avg" : { "field" : "price" } }
            }
        }
    }
}

11、嵌套聚合-廣度優(yōu)先

說一個應(yīng)用于場景: 我們檢索電影的評論凯砍, 但是我們先按照演員分組聚合箱硕,再按照評論的數(shù)量進(jìn)行聚合。且我們假設(shè)每個演員都出演了10部電影悟衩。

分析: 如果我們選擇深度優(yōu)先的話剧罩, ES在構(gòu)建演員電影相關(guān)信息時,會順道計(jì)算出電影下面評論數(shù)的信息座泳,假如說有10萬個演員的filter aggregate話惠昔, 10萬*10=100萬個電影 每個電影下又有很多影評,接著處理影評挑势, 就這樣內(nèi)存中可能會存在幾百萬條數(shù)據(jù)镇防,但是我們最終就需要50條,這種開銷是很大的潮饱。

廣度優(yōu)先的話来氧,是我們先處理電影數(shù),而不管電影的評論數(shù)的聚合情況香拉,先從10萬演員中干掉99990條數(shù)據(jù)啦扬,剩下10個演員再聚合。

        "aggs":{
            "target_actors":{
                "terms":{
                    "field":"actors",
                    "size":10,
                    "collect_mode":"breadth_first" # 廣度優(yōu)先
                }
            }
        }

12凫碌、global aggregation

全局聚合考传,下面先使用query進(jìn)行全文檢索,然后進(jìn)行聚合证鸥, 下面的聚合實(shí)際上是針對兩個不同的結(jié)果進(jìn)行聚合僚楞。

  • 第一個聚合添加了global關(guān)鍵字,意思是ES中存在的所有doc進(jìn)行聚合計(jì)算得出t-shirt的平均價格

  • 第二個聚合針對全文檢索的結(jié)果進(jìn)行聚合

POST /sales/_search?size=0
{
    "query" : {
        # 全文檢索 type = t-shirt的商品
        "match" : { "type" : "t-shirt" }
    },
    "aggs" : {
        "all_products" : {
            "global" : {}, # 表示讓 all_products 對ES中所有數(shù)據(jù)進(jìn)行聚合
            "aggs" : {
                # 沒有g(shù)lobal關(guān)鍵字枉层,表示針對全文檢索的結(jié)果進(jìn)行聚合
                "avg_price" : { "avg" : { "field" : "price" } }
            }
        },
        "t_shirts": { "avg" : { "field" : "price" } }
    }
}

13泉褐、Cardinality Aggregate 基數(shù)聚合

在ES中聚合時去重一般選用cardinality metric,它可以實(shí)現(xiàn)對每一個bucket中指定的field進(jìn)行去重鸟蜡,最終得到去重后的count值膜赃。

雖然她會存在5%左右的錯誤率,但是性能特別好

POST /sales/_search?size=0
{
    "aggs" : {
        # 先按照月份聚合得到不同月的bucket
        "agg_by_month" : {
            "date_histogram":{
              "field" : "my_month",
              "internal":"month"
            }
        },
                # 在上一步得到的以月份為維護(hù)劃分的bucket基礎(chǔ)上揉忘,再按照品牌求基數(shù)去重跳座。
              # 于是最終我們就得到了每個月、每種品牌的銷售量泣矛。
        "aggs" : {
            "dis_by_brand" : {
                "cardinality" : { 
                 "field" : "brand"
            }
        }
    }
}

對Cardinality Aggregate的性能優(yōu)化疲眷, 添加 precision_threshold 優(yōu)化準(zhǔn)確率和內(nèi)存的開銷。

還是下面的例子您朽,如果將precision_threshold的值調(diào)整到100意思是:當(dāng)品牌的總數(shù)量小于100時狂丝,去重的精準(zhǔn)度為100%, 此時內(nèi)存的占用情況為 100*8=800字節(jié)。

加入我們將這個值調(diào)整為1000几颜,意思是當(dāng)品臺的種類在1000個以內(nèi)時倍试,去重的精準(zhǔn)度100%,內(nèi)存的占用率為1000*8=80KB蛋哭。

官方給出的指標(biāo)是:將precision_threshold設(shè)置為5時县习,錯誤率會被控制在5%以內(nèi)。

POST /sales/_search?size=0
{
    "aggs" : {
        "type_count" : {
            "cardinality" : { # 關(guān)鍵字
                "field" : "brand"
                "precision_threshold":100
            }
        }
    }
}

進(jìn)一步優(yōu)化谆趾,Cardinality底層使用的算法是 HyperLogLog++准颓。

因?yàn)檫@個算法的底層會對所有的 unique value取hash值,利用這個hash值去近似的求distcint count棺妓, 因此我們可以在創(chuàng)建mapping時,將這個hash的求法設(shè)置好炮赦,添加doc時怜跑,一并計(jì)算出這個hash值,這樣 HyperLogLog++ 就無需再計(jì)算hash值吠勘,而是直接使用性芬。從而達(dá)到優(yōu)化速度的效果。

PUT /index/
{
    "mappings":{
        "my_type":{
            "properties":{
                "my_field":{
                    "type":"text",
                    "fields":{
                        "hash":{
                            "type":"murmu3"
                        }
                    }
                }
            }
        }
    }
}

14剧防、控制聚合的升降序

比如我想知道每種顏色item的平均價格植锉,并且我希望按照價格的從小到大升序展示給我看。

于是就像下面這樣峭拘,先按照顏色聚合可以將相同顏色的item聚合成1組俊庇,在聚合的結(jié)果上再根據(jù)價格進(jìn)行聚合。期望在最終的結(jié)果中鸡挠,通過order控制按照價格聚合的分組中升序排序辉饱, 這算是個在下鉆分析時的排序技巧。

GET /index/type/_search
{
     "size":0拣展,
     "aggs":{
         "group_by_color":{
             "term":{
                 "field":"color",
                 "order":{ #
                     "avg_price":"asc"
                 }
             }
         },
         "aggs":{
             # 在上一層按color聚合的基礎(chǔ)上彭沼,再針對price進(jìn)行聚合
             "avg_price":{
                 "avg":{
                     "field":"price"
                 }
             }
         }
     }
}

15、Percentiles Aggregation

計(jì)算百分比备埃, 常用它計(jì)算:在200ms內(nèi)成功訪問網(wǎng)站的比率姓惑、在500ms內(nèi)成功訪問網(wǎng)站的比例、在1000ms內(nèi)成功訪問網(wǎng)站的比例按脚,或者是銷售價為1000元的商品占總銷售量的比例于毙、銷售價為2000元的商品占總銷售量的比例等等。

示例: 針對doc中的 load_time字段辅搬, 計(jì)算出在不同百分比下面的 load_time_outliner情況望众。

GET latency/_search
{
    "size": 0,
    "aggs" : {
        "load_time_outlier" : {
                # 關(guān)鍵字
            "percentiles" : {
                "field" : "load_time" 
            }
        }
    }
}

響應(yīng)解讀:在百分之50的加載請求中,平均load_time的時間是在445.0烂翰。 在99%的請求中夯缺,平均加載時間980.1。

{
    ...

   "aggregations": {
      "load_time_outlier": {
         "values" : {
            "1.0": 9.9,
            "5.0": 29.500000000000004,
            "25.0": 167.5,
            "50.0": 445.0,
            "75.0": 722.5,
            "95.0": 940.5,
            "99.0": 980.1000000000001
         }
      }
   }
}

還可以自己指定百分比跨度間隔甘耿。

GET latency/_search
{
    "size": 0踊兜,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "field" : "load_time",
                "percents" : [95,99,99.9] 
            }
        }
    }
}

優(yōu)化: percentile底層使用的是 TDigest算法。用很多個節(jié)點(diǎn)執(zhí)行百分比計(jì)算佳恬,近似估計(jì)捏境,有誤差,節(jié)點(diǎn)越多毁葱,越精準(zhǔn)垫言。

可以設(shè)置compression的值, 默認(rèn)是100 倾剿, ES限制節(jié)點(diǎn)的最多是 compression*20 =2000個node去計(jì)算 筷频, 因?yàn)楣?jié)點(diǎn)越多,性能就越差前痘。

一個節(jié)點(diǎn)占用 32字節(jié)凛捏, 1002032 = 64KB。

GET latency/_search
{
    "size": 0芹缔,
    "aggs" : {
        "load_time_outlier" : {
            "percentiles" : {
                "field" : "load_time",
                "percents" : [95,99,99.9],
                "compression":100 # 默認(rèn)值100
            }
        }
    }
}

參考:https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-aggregations.html




五坯癣、7個查詢優(yōu)化技巧




  • 第一種:多字段檢索,巧妙控制權(quán)重
  • 第一種: 更換寫法最欠,改變占用的權(quán)重比例示罗。
  • 第三種: 如果不希望使用相關(guān)性得分,使用下面的語法芝硬。
  • 第四種: 靈活的查詢
  • 第五種: 比如我對title字段進(jìn)行檢索鹉勒,我希望檢索結(jié)果中包含"java",并且我允許檢索結(jié)果中包含:”golang“ 吵取,但是禽额!如果檢索結(jié)果中包含”golang“,我希望這個title中包含”golang“的doc的排名能靠后一些皮官。
  • 第六種: 重打分機(jī)制
  • 第七種: 提高召回率和精準(zhǔn)度的技巧:混用match和match_phrase+slop提高召回率脯倒。注意下面的嵌套查詢層級 bool、must捺氢、should




上面的七種優(yōu)化相關(guān)性得分的方式的具體實(shí)現(xiàn)代碼藻丢,在公眾號原文中可以查看到,推薦閱讀原文摄乒,json的格式會好看很多悠反,ES專題依然在連載中~残黑,歡迎關(guān)注。

點(diǎn)擊閱讀原文斋否,查看7種優(yōu)化方式的具體實(shí)現(xiàn)代碼
點(diǎn)擊閱讀原文梨水,查看7種優(yōu)化方式的具體實(shí)現(xiàn)代碼
點(diǎn)擊閱讀原文,查看7種優(yōu)化方式的具體實(shí)現(xiàn)代碼


參考:

官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/6.0

query dsl:https://www.elastic.co/guide/en/elasticsearch/reference/6.2/query-dsl.html

聚合分析:https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-aggregations.html




歡迎關(guān)注

點(diǎn)擊閱讀原文茵臭,怎么關(guān)注我你懂的~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疫诽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子旦委,更是在濱河造成了極大的恐慌奇徒,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缨硝,死亡現(xiàn)場離奇詭異摩钙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)查辩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門胖笛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宜肉,你說我怎么就攤上這事◆岜” “怎么了谬返?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長日杈。 經(jīng)常有香客問我遣铝,道長,這世上最難降的妖魔是什么莉擒? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任酿炸,我火速辦了婚禮,結(jié)果婚禮上涨冀,老公的妹妹穿的比我還像新娘填硕。我一直安慰自己,他們只是感情好鹿鳖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布扁眯。 她就那樣靜靜地躺著,像睡著了一般翅帜。 火紅的嫁衣襯著肌膚如雪姻檀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天涝滴,我揣著相機(jī)與錄音绣版,去河邊找鬼胶台。 笑死,一個胖子當(dāng)著我的面吹牛杂抽,可吹牛的內(nèi)容都是我干的诈唬。 我是一名探鬼主播茂装,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼象颖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了家淤?” 一聲冷哼從身側(cè)響起匙睹,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤愚屁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后痕檬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體霎槐,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年梦谜,在試婚紗的時候發(fā)現(xiàn)自己被綠了丘跌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡唁桩,死狀恐怖闭树,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荒澡,我是刑警寧澤报辱,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站单山,受9級特大地震影響碍现,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜米奸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一昼接、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧悴晰,春花似錦慢睡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至佃却,卻和暖如春者吁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饲帅。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工复凳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘤泪,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓育八,卻偏偏與公主長得像对途,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子髓棋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容