日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

(六)ElasticSearch 6.1.1聚合查询

發(fā)布時(shí)間:2023/12/10 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (六)ElasticSearch 6.1.1聚合查询 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1 普通類型

1.1 基本操作

1.1.1 導(dǎo)入實(shí)戰(zhàn)數(shù)據(jù)

數(shù)據(jù)字段如下:

字段類型作用
pricelong汽車售價(jià)
colortext汽車顏色
maketext汽車品牌
solddate銷售日期
# 創(chuàng)建索引 PUT /cars {"mappings" : {"transactions" : {"properties" : {"color" : {"type" : "keyword"},"make" : {"type" : "keyword"},"price" : {"type" : "long"},"sold" : {"type" : "date"}}}} }# 導(dǎo)入數(shù)據(jù) POST /cars/transactions/_bulk { "index": {}} { "price" : 10000, "color" : "red", "make" : "honda", "sold" : "2014-10-28" } { "index": {}} { "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" } { "index": {}} { "price" : 30000, "color" : "green", "make" : "ford", "sold" : "2014-05-18" } { "index": {}} { "price" : 15000, "color" : "blue", "make" : "toyota", "sold" : "2014-07-02" } { "index": {}} { "price" : 12000, "color" : "green", "make" : "toyota", "sold" : "2014-08-19" } { "index": {}} { "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" } { "index": {}} { "price" : 80000, "color" : "red", "make" : "bmw", "sold" : "2014-01-01" } { "index": {}} { "price" : 25000, "color" : "blue", "make" : "ford", "sold" : "2014-02-12" }

1.1.2 最簡單的聚合:terms桶

# 第一個(gè)聚合命令是terms桶,相當(dāng)于SQL中的group by,將所有記錄按照顏色聚合 GET /cars/transactions/_search {"size":0,"aggs":{"popular_colors":{"terms": {"field": "color"}} } }

1.1.3 添加度量指標(biāo)

  • 上面的示例返回的是每個(gè)桶中的文檔數(shù)量,接下es支持豐富的指標(biāo),例如平均值(Avg)、最大值(Max)、最小值(Min)、累加和(Sum)等,接下來試試?yán)奂雍偷挠梅?#xff1b;
  • 下面請(qǐng)求的作用是統(tǒng)計(jì)每種顏色汽車的銷售總額:
GET /cars/transactions/_search {"size":0,"aggs":{"colors":{"terms": {"field": "color"},"aggs":{"sales":{"sum":{"field":"price"}}}} } }# 解釋 GET /cars/transactions/_search {"size":0,"aggs":{ ------和前面一樣,指定聚合操作"colors":{ ------別名"terms": { ------桶類型是按指定字段聚合"field": "color" ------按照color字段聚合},"aggs":{ ------新增的aggs對(duì)象,用于處理聚合在每個(gè)桶內(nèi)的文檔"sales":{ ------別名"sum":{ ------度量指標(biāo)是指定字段求和"field":"price" ---求和的字段是price}}}} } }"aggregations" : { ------聚合結(jié)果"colors" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [ ------這個(gè)json數(shù)組的每個(gè)對(duì)象代表一個(gè)桶{"key" : "red", ------該桶將所有color等于red的文檔聚合進(jìn)來"doc_count" : 4, ------有4個(gè)color等于red的文檔"sales" : { ------這里面是sum計(jì)算后的結(jié)果 "value" : 130000.0 ------所有color等于red的汽車銷售總額}},{"key" : "blue","doc_count" : 2,"sales" : {"value" : 40000.0 ------所有color等于blue的汽車銷售總額}},

1.2 區(qū)間聚合

1.2.1條形圖(histogram桶)

以汽車銷售記錄為例做一次聚合查詢,為售價(jià)創(chuàng)建histogram桶,以20000作為間隔,每個(gè)桶負(fù)責(zé)的區(qū)間如上圖所示,相關(guān)的銷售記錄就會(huì)被放入對(duì)應(yīng)的桶中,請(qǐng)求參數(shù)和說明如下:

# 可執(zhí)行查詢 GET /cars/transactions/_search {"size":0, "aggs":{ "price":{ "histogram": { "field": "price", "interval": 20000 }} } } # 解釋 GET /cars/transactions/_search {"size":0, ---令返回值的hits對(duì)象為空"aggs":{ ---聚合命令"price":{ ---聚合字段名稱"histogram": { ---桶類型"field": "price", ---指定price字段的值作為判斷條件"interval": 20000 ---每個(gè)桶負(fù)責(zé)的區(qū)間大小為20000}} } }# 返回結(jié)果"aggregations" : { ---聚合結(jié)果"price" : { ---請(qǐng)求參數(shù)中指定的名稱"buckets" : [ ---price桶的數(shù)據(jù)在此數(shù)組中{"key" : 0.0, ---第一個(gè)桶,區(qū)間[0-19999],0.0是起始值"doc_count" : 3 ---這個(gè)區(qū)間有三個(gè)文檔(price值分別是10000、12000、15000)},{"key" : 20000.0, ---第二個(gè)桶,區(qū)間[20000-39999],20000.0是起始值"doc_count" : 4 ---這個(gè)區(qū)間有四個(gè)文檔},{"key" : 40000.0, ---第三個(gè)桶,區(qū)間[40000-59999],40000.0是起始值"doc_count" : 0 ---這個(gè)區(qū)間沒有文檔},......

1.2.2 控制空桶是否返回

在上面的返回值中,第三個(gè)桶中沒有文檔,在有的業(yè)務(wù)場景中,我們不需要沒有數(shù)據(jù)的桶,此時(shí)可以用min_doc_count參數(shù)來控制,如果min_doc_count等于2,表示桶中最少有兩條記錄才會(huì)出現(xiàn)在返回內(nèi)容中,如下所示,min_doc_count如果等于1,那么空桶就不會(huì)被es返回了:

GET /cars/transactions/_search {"size":0,"aggs":{"price":{"histogram": {"field": "price","interval": 20000,"min_doc_count": 1}} } }

1.2.3 histogram桶加metrics

上面的例子返回結(jié)果只有每個(gè)桶內(nèi)的文檔數(shù),也可以加入metrics對(duì)桶中的數(shù)據(jù)進(jìn)行處理,例如計(jì)算每個(gè)區(qū)間內(nèi)的最高價(jià)、最低價(jià)、平均售價(jià),可以加入max、min、avg參數(shù),如下:

# 可執(zhí)行查詢 GET /cars/transactions/_search {"size":0, "aggs":{ "price":{ "histogram": { "field": "price", "interval": 20000, "min_doc_count": 1},"aggs": { "max_price": { "max":{ "field": "price" }},"min_price": { "min":{ "field": "price" }},"avg_price": { "avg":{ "field": "price" }}}} } }# 解釋 GET /cars/transactions/_search {"size":0, ---令返回值的hits對(duì)象為空"aggs":{ ---聚合命令"price":{ ---聚合字段名稱"histogram": { ---桶類型"field": "price", ---指定price字段的值作為判斷條件"interval": 20000 ---每個(gè)桶負(fù)責(zé)的區(qū)間大小為20000},"aggs": { ---表示對(duì)桶內(nèi)數(shù)據(jù)做metrics"max_price": { ---指定metrics處理結(jié)果的字段名"max":{ ---metrics類型為max"field": "price" ---指定取price字段的值做最大值比較}},"min_price": { ---指定metrics處理結(jié)果的字段名"min":{ ---metrics類型為min"field": "price" ---指定取price字段的值做最小值比較}},"avg_price": { ---指定metrics處理結(jié)果的字段名"avg":{ ---metrics類型為avg"field": "price" ---指定取price字段的值計(jì)算平均值}}}} } }# 返回結(jié)果"aggregations" : { ---聚合結(jié)果"price" : { ---請(qǐng)求參數(shù)中指定的名稱"buckets" : [ ---price桶的數(shù)據(jù)在此數(shù)組中{"key" : 0.0, ---第一個(gè)區(qū)間[0-19999],0.0是起始值"doc_count" : 3, ---這個(gè)區(qū)間有三條記錄(price值分別是10000、12000、15000)"max_price" : { ---指定的metrics結(jié)果名稱"value" : 15000.0 ---桶中有三個(gè)文檔,price字段的最大值是15000},"min_price" : {"value" : 10000.0 ---桶中有三個(gè)文檔,price字段的最小值是10000},"avg_price" : {"value" : 12333.333333333334 ---桶中有三個(gè)文檔,price字段的平均值是12333.333333333334}},......

1.2.4 時(shí)間區(qū)間的桶(date_histogram)

  • histogram桶可以實(shí)現(xiàn)按照時(shí)間分段么?如果用毫秒數(shù)來處理,似乎是可以的,但是對(duì)年月日的處理就力不從心了,常見的時(shí)間區(qū)間處理,用date_histogram桶即可滿足要求;
  • 下面就是date_histogram桶的用法:每月銷售多少臺(tái)汽車:
GET /cars/transactions/_search { # 可執(zhí)行查詢 GET /cars/transactions/_search {"size": 0, "aggs": { "sales": { "date_histogram": { "field": "sold", "interval": "month", "format": "yyyy-MM-dd" },"aggs": { "max_price": { "max":{ "field": "price" }},"min_price": { "min":{ "field": "price" }}}}} }# 解釋"size": 0, ---令返回值的hits對(duì)象為空"aggs": { ---聚合命令"sales": { ---聚合字段名稱"date_histogram": { ---桶類型"field": "sold", ---用sold字段的值作進(jìn)行時(shí)間區(qū)間判斷"interval": "month", ---間隔單位是月"format": "yyyy-MM-dd" ---返回的數(shù)據(jù)中,時(shí)間字段格式},"aggs": { ---表示對(duì)桶內(nèi)數(shù)據(jù)做metrics"max_price": { ---指定metrics處理結(jié)果的字段名"max":{ ---metrics類型為max"field": "price" ---指定取price字段的值做最大值比較}},"min_price": { ---指定metrics處理結(jié)果的字段名"min":{ ---metrics類型為min"field": "price" ---指定取price字段的值做最小值比較}}}}} }# es返回 "aggregations" : { ---聚合結(jié)果"sales" : { ---請(qǐng)求參數(shù)中指定的名稱"buckets" : [ ---sales桶的數(shù)據(jù)在此數(shù)組中{"key_as_string" : "2014-01-01", ---請(qǐng)求的format參數(shù)指定了key的格式"key" : 1388534400000, ---真正的時(shí)間字段"doc_count" : 1, ---2014年1月份的文檔數(shù)量"max_price" : { ---2014年1月的文檔做了metrics類型為max的處理后,結(jié)果在此"value" : 80000.0 ---2014年1月的文檔中,price字段的最大值},"min_price" : { ---2014年1月的文檔做了metrics類型為min的處理后,結(jié)果在此"value" : 80000.0 ---2014年1月的文檔中,price字段的最大值}},{"key_as_string" : "2014-02-01","key" : 1391212800000,"doc_count" : 1,"max_price" : {"value" : 25000.0},"min_price" : {"value" : 25000.0}},......

1.2.5 連續(xù)多次聚合

連續(xù)分桶,第二次分桶一定是在第一次分桶的基礎(chǔ)上,對(duì)每一個(gè)桶再進(jìn)行二次分桶,這一點(diǎn)可以在{}范圍上看出,global關(guān)鍵字可以突破這個(gè)限制,但是兩次分桶的結(jié)果仍然遵循{}的層次,這一點(diǎn)可以在全局桶體會(huì)到。

  • 來做一個(gè)略為復(fù)雜的聚合操作:按季度展示每個(gè)汽車品牌的銷售總額;
  • 操作的第一步是按照時(shí)間區(qū)間做聚合,然后在每個(gè)桶中,將文檔按照品牌做第二次聚合,第二次聚合的結(jié)果也可以理解為多個(gè)桶,每個(gè)桶中的文檔,是某個(gè)平臺(tái)在某個(gè)季度的銷售總額;
# 可執(zhí)行 GET /cars/transactions/_search {"size": 0, "aggs": { "sales": { "date_histogram": { "field": "sold", "interval": "1q", "format": "yyyy-MM-dd", "min_doc_count": 1 },"aggs": { "per_make_sum": { "terms": { "field": "make" },"aggs": { "sum_price": { "sum": { "field": "price" }}}}}} } }# 解釋 GET /cars/transactions/_search {"size": 0, ---令返回值的hits對(duì)象為空"aggs": { ---聚合命令"sales": { ---聚合字段名稱"date_histogram": { ---桶類型為時(shí)間區(qū)間"field": "sold", ---指定sold字段的值作為判斷條件"interval": "1q", ---區(qū)間間隔為1季度"format": "yyyy-MM-dd", ---返回的桶的key,被格式化時(shí)的格式"min_doc_count": 1 ---空桶不返回},"aggs": { ---第二層桶"per_make_sum": { ---聚合字段名稱"terms": { ---桶類型為terms"field": "make" ---按照make字段聚合},"aggs": { ---第二層桶的metrics"sum_price": { ---聚合字段名稱"sum": { ---metrics處理,累加"field": "price" ---取price字段的值累加}}}}}}} }# es返回 "aggregations" : {"sales" : {"buckets" : [ ---聚合結(jié)果{"key_as_string" : "2014-01-01", ---當(dāng)前桶的key的格式化后的值"key" : 1388534400000, ---當(dāng)前桶的key原值"doc_count" : 2, ---當(dāng)前桶中文檔數(shù)"per_make_sum" : { ---第二層桶的名稱"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [ ---第二層聚合結(jié)果{"key" : "bmw", ---聚合字段的值,這里是汽車品牌"doc_count" : 1, ---桶內(nèi)的文檔數(shù)量"sum_price" : { ---metrics處理結(jié)果名稱"value" : 80000.0 ---metrics處理結(jié)果,這里是銷售額累加值}},{"key" : "ford", ---聚合字段的值,這里是汽車品牌"doc_count" : 1, ---桶內(nèi)的文檔數(shù)量"sum_price" : { ---metrics處理結(jié)果名稱"value" : 25000.0 ---metrics處理結(jié)果,這里是銷售額累加值

1.3 范圍限定

1.3.1 最簡單的查詢范圍

福特汽車一共分為幾種顏色?這就是最簡單的范圍限定聚合(限定了汽車品牌),查詢DSL如下:

# 可執(zhí)行 GET /cars/transactions/_search {"size":0,"query": { "term": { "make": "ford" }}, "aggs":{ "popular_colors":{ "terms": { "field": "color" }} } }# 解釋 GET /cars/transactions/_search {"size":0,"query": { ---范圍限定的查詢"term": { ---查詢類型是精確匹配"make": "ford" ---查詢條件是品牌為福特}}, "aggs":{ ---聚合"popular_colors":{ ---聚合字段名"terms": { ---桶類型"field": "color" ---匹配字段是color}} } }# es返回"aggregations" : { ---聚合結(jié)果"popular_colors" : { ---聚合字段"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [ ---這個(gè)數(shù)組的元素是所有的桶{"key" : "blue", ---color為blue的文檔"doc_count" : 1 ---文檔數(shù)為1},{"key" : "green", ---color為blue的文檔"doc_count" : 1 ---文檔數(shù)為1}]}} }

1.3.2 全局桶

如果想對(duì)比福特汽車的銷售額和所有汽車的銷售額,可以通過全局桶對(duì)所有文檔做聚合,關(guān)鍵字是global,全局桶的聚合不受范圍限定的影響:

# 可執(zhí)行 GET /cars/transactions/_search {"size": 0,"query": { "term": { "make": "ford" }},"aggs": { "ford_sales": { "sum": { "field": "price" }},"all": { "global": {}, "aggs": { "all_sales": { "sum": { "field": "price" }}}}} }# 解釋 GET /cars/transactions/_search {"size": 0,"query": { ---范圍限定的查詢"term": { ---查詢類型是精確匹配"make": "ford" ---查詢條件是品牌為福特}},"aggs": { ---聚合"ford_sales": { ---聚合字段名"sum": { ---直接對(duì)范圍內(nèi)的所有文檔執(zhí)行metrics,類型是累加"field": "price" ---選擇price字段的值進(jìn)行累加}},"all": { ---聚合字段名"global": {}, ---全局桶關(guān)鍵字,表示忽略前面term查詢的范圍限定"aggs": { ---聚合"all_sales": { ---聚合字段名"sum": { ---直接對(duì)范圍內(nèi)的所有文檔執(zhí)行metrics,類型是累加"field": "price" ---選擇price字段的值進(jìn)行累加}}}}} } # es返回 ......"aggregations" : { ---聚合結(jié)果"all" : { ---全局桶的聚合結(jié)果(term查詢無效)"doc_count" : 8, ---文檔總數(shù)"all_sales" : { ---聚合字段名"value" : 212000.0 ---總銷售額}},"ford_sales" : { ---聚合字段名(term查詢限定了范圍,只有福特汽車的銷售記錄)"value" : 55000.0 ---福特汽車銷售額}} }

1.3.3 使用filter提高查詢性能

雖然query和filter限定范圍的結(jié)果是一樣的,但是filter會(huì)忽略評(píng)分,并且有可能緩存結(jié)果數(shù)據(jù),這些都是性能上的優(yōu)勢。
前面的范圍限定用到了query,其實(shí)適用于查詢的過濾器也能應(yīng)用在聚合操作中,下面是過濾+聚合的查詢,和前面一樣,也是統(tǒng)計(jì)總銷售和和福特汽車的銷售額:

# 可執(zhí)行 GET /cars/transactions/_search {"size": 0,"query": {"bool": { "filter": { "term": { "make": "ford" }}}},"aggs": { "ford_sales": { "sum": { "field": "price" }},"all": { "global": {}, "aggs": { "all_sales": { "sum": { "field": "price" }}}}} }# 解釋 GET /cars/transactions/_search {"size": 0,"query": {"bool": { ---布爾查詢,里面可以將query和filter組合使用"filter": { ---本例只用到了filter"term": { ---精確匹配"make": "ford" ---匹配福特品牌 }}}},"aggs": { ---聚合結(jié)果"ford_sales": { ---聚合字段名"sum": { ---metrics操作,累加"field": "price" ---累加字段是price}},"all": { ---聚合字段名 "global": {}, ---全局桶關(guān)鍵字,表示忽略范圍限定"aggs": { ---聚合"all_sales": { ---聚合字段名"sum": { ---metrics操作,累加"field": "price" ---累加字段是price}}}}} }

1.3.4 桶內(nèi)filter

學(xué)習(xí)桶內(nèi)filter之前,先看看官方的布爾查詢DSL,如下所示,查詢JSON對(duì)象的內(nèi)部可以加入filter,對(duì)查詢結(jié)果做過濾:

GET /_search {"query": { "bool": { "must": [ ---布爾查詢{ "match": { "title": "Search" }}, { "match": { "content": "Elasticsearch" }} ],"filter": [ ---對(duì)查詢結(jié)果做過濾{ "term": { "status": "published" }}, { "range": { "publish_date": { "gte": "2015-01-01" }}} ]}} }
  • 桶內(nèi)filter和布爾查詢中的filter類似,對(duì)進(jìn)入桶中的數(shù)據(jù)可以加入filter,這樣桶內(nèi)的數(shù)據(jù)就是此filter過濾后的數(shù)據(jù)了;
  • 舉個(gè)例子,統(tǒng)計(jì)藍(lán)色的福特汽車銷售額,首先限定品牌范圍,這個(gè)可以直接用之前的限定方式,然后在桶內(nèi)加入一個(gè)filter,只保留顏色為藍(lán)色的文檔:
GET /cars/transactions/_search {"size": 0,"query": {"bool": { ---布爾查詢,里面可以將query和filter組合使用"filter": { ---本例只用到了filter"term": { ---精確匹配"make": "ford" ---匹配福特品牌 }}}},"aggs": {"sales": {"filter": { ---桶內(nèi)filter"term": { ---精確匹配"color": "blue" ---匹配藍(lán)色}},"aggs": {"blue_sales": {"sum": { ---metrics操作,累加"field": "price"}}}}} }# es返回"hits" : {"total" : 2,"max_score" : 0.0,"hits" : [ ]},"aggregations" : {"sales" : {"doc_count" : 1,"green_sales" : {"value" : 25000.0}}} }

1.4 結(jié)果排序

1.4.1 默認(rèn)排序

之前文章中的聚合查詢,我們都沒有做排序設(shè)置,此時(shí)es會(huì)用每個(gè)桶的doc_count字段做降序,下圖是個(gè)terms桶聚合的示例,可見返回了三個(gè)bucket對(duì)象,是按照doc_count字段降序排列的:

1.4.2 內(nèi)置排序

除了自定義排序,es自身也內(nèi)置了兩種排序參數(shù),可以直接拿來使用:

# _count:這個(gè)參數(shù)對(duì)應(yīng)的就是doc_count,以下請(qǐng)求的排序效果和默認(rèn)的排序效果是一致 GET /cars/transactions/_search {"size":0,"aggs":{"popular_colors":{"terms": {"field": "color","order": { ---表示要對(duì)聚合結(jié)果做排序"_count": "desc" ---排序字段是doc_count,順序是降序}}} } }# _key:在區(qū)間聚合的時(shí)候(histogram或者date_histogram),可以根據(jù)桶的key做排序: GET /cars/transactions/_search {"size": 0,"aggs": {"price": {"histogram": { ---區(qū)間聚合"field": "price", ---取price字段的值"interval": 20000, ---每個(gè)區(qū)間的大小是20000"order": { ---表示要對(duì)聚合結(jié)果做排序"_key": "desc" ---排序字段是桶的key值,這里是每個(gè)區(qū)間的起始值,順序是降序}}}} } # es返回......"aggregations" : {"price" : {"buckets" : [{"key" : 80000.0,"doc_count" : 1},{"key" : 60000.0,"doc_count" : 0},{"key" : 40000.0,"doc_count" : 0},{"key" : 20000.0,"doc_count" : 4},{"key" : 0.0,"doc_count" : 3}]}} }

2 nested類型

2.1 一個(gè)官網(wǎng)例子

A special single bucket aggregation that enables aggregating nested documents.
For example, lets say we have an index of products, and each product holds the list of resellers - each having its own price for the product. The mapping could look like:

# 可執(zhí)行 # resellers is an array that holds nested documents. PUT /products {"mappings": {"Apple":{"properties" : {"resellers" : { "type" : "nested","properties" : {"reseller" : { "type" : "text" },"price" : { "type" : "double" }}}}}} }# We are using a dynamic mapping for the name attribute. PUT /products/Apple/0 {"name": "LED TV", "resellers": [{"reseller": "companyA","price": 350},{"reseller": "companyB","price": 500}] }# The following request returns the minimum price a product can be purchased for GET /products/_search {"size": 0,"query" : {"match" : { "name" : "led tv" }},"aggs" : {"resellers" : {"nested" : {"path" : "resellers"},"aggs" : {"min_price" : { "min" : { "field" : "resellers.price" } }}}} }

As you can see above, the nested aggregation requires the path of the nested documents within the top level documents. Then one can define any type of aggregation over these nested documents.

{..."aggregations": {"resellers": {"doc_count": 2,"min_price": {"value": 350}

參考資料

  • https://blog.csdn.net/boling_cavalry/article/details/89735952 詳細(xì)講解了聚合查詢
  • https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-nested-aggregation.html官網(wǎng)例子
  • 總結(jié)

    以上是生活随笔為你收集整理的(六)ElasticSearch 6.1.1聚合查询的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。