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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

(六)ElasticSearch 6.1.1聚合查询

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

1 普通類型

1.1 基本操作

1.1.1 導入實戰數據

數據字段如下:

字段類型作用
pricelong汽車售價
colortext汽車顏色
maketext汽車品牌
solddate銷售日期
# 創建索引 PUT /cars {"mappings" : {"transactions" : {"properties" : {"color" : {"type" : "keyword"},"make" : {"type" : "keyword"},"price" : {"type" : "long"},"sold" : {"type" : "date"}}}} }# 導入數據 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桶

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

1.1.3 添加度量指標

  • 上面的示例返回的是每個桶中的文檔數量,接下es支持豐富的指標,例如平均值(Avg)、最大值(Max)、最小值(Min)、累加和(Sum)等,接下來試試累加和的用法;
  • 下面請求的作用是統計每種顏色汽車的銷售總額:
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對象,用于處理聚合在每個桶內的文檔"sales":{ ------別名"sum":{ ------度量指標是指定字段求和"field":"price" ---求和的字段是price}}}} } }"aggregations" : { ------聚合結果"colors" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [ ------這個json數組的每個對象代表一個桶{"key" : "red", ------該桶將所有color等于red的文檔聚合進來"doc_count" : 4, ------有4個color等于red的文檔"sales" : { ------這里面是sum計算后的結果 "value" : 130000.0 ------所有color等于red的汽車銷售總額}},{"key" : "blue","doc_count" : 2,"sales" : {"value" : 40000.0 ------所有color等于blue的汽車銷售總額}},

1.2 區間聚合

1.2.1條形圖(histogram桶)

以汽車銷售記錄為例做一次聚合查詢,為售價創建histogram桶,以20000作為間隔,每個桶負責的區間如上圖所示,相關的銷售記錄就會被放入對應的桶中,請求參數和說明如下:

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

1.2.2 控制空桶是否返回

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

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

1.2.3 histogram桶加metrics

上面的例子返回結果只有每個桶內的文檔數,也可以加入metrics對桶中的數據進行處理,例如計算每個區間內的最高價、最低價、平均售價,可以加入max、min、avg參數,如下:

# 可執行查詢 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對象為空"aggs":{ ---聚合命令"price":{ ---聚合字段名稱"histogram": { ---桶類型"field": "price", ---指定price字段的值作為判斷條件"interval": 20000 ---每個桶負責的區間大小為20000},"aggs": { ---表示對桶內數據做metrics"max_price": { ---指定metrics處理結果的字段名"max":{ ---metrics類型為max"field": "price" ---指定取price字段的值做最大值比較}},"min_price": { ---指定metrics處理結果的字段名"min":{ ---metrics類型為min"field": "price" ---指定取price字段的值做最小值比較}},"avg_price": { ---指定metrics處理結果的字段名"avg":{ ---metrics類型為avg"field": "price" ---指定取price字段的值計算平均值}}}} } }# 返回結果"aggregations" : { ---聚合結果"price" : { ---請求參數中指定的名稱"buckets" : [ ---price桶的數據在此數組中{"key" : 0.0, ---第一個區間[0-19999],0.0是起始值"doc_count" : 3, ---這個區間有三條記錄(price值分別是10000、12000、15000)"max_price" : { ---指定的metrics結果名稱"value" : 15000.0 ---桶中有三個文檔,price字段的最大值是15000},"min_price" : {"value" : 10000.0 ---桶中有三個文檔,price字段的最小值是10000},"avg_price" : {"value" : 12333.333333333334 ---桶中有三個文檔,price字段的平均值是12333.333333333334}},......

1.2.4 時間區間的桶(date_histogram)

  • histogram桶可以實現按照時間分段么?如果用毫秒數來處理,似乎是可以的,但是對年月日的處理就力不從心了,常見的時間區間處理,用date_histogram桶即可滿足要求;
  • 下面就是date_histogram桶的用法:每月銷售多少臺汽車:
GET /cars/transactions/_search { # 可執行查詢 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對象為空"aggs": { ---聚合命令"sales": { ---聚合字段名稱"date_histogram": { ---桶類型"field": "sold", ---用sold字段的值作進行時間區間判斷"interval": "month", ---間隔單位是月"format": "yyyy-MM-dd" ---返回的數據中,時間字段格式},"aggs": { ---表示對桶內數據做metrics"max_price": { ---指定metrics處理結果的字段名"max":{ ---metrics類型為max"field": "price" ---指定取price字段的值做最大值比較}},"min_price": { ---指定metrics處理結果的字段名"min":{ ---metrics類型為min"field": "price" ---指定取price字段的值做最小值比較}}}}} }# es返回 "aggregations" : { ---聚合結果"sales" : { ---請求參數中指定的名稱"buckets" : [ ---sales桶的數據在此數組中{"key_as_string" : "2014-01-01", ---請求的format參數指定了key的格式"key" : 1388534400000, ---真正的時間字段"doc_count" : 1, ---2014年1月份的文檔數量"max_price" : { ---2014年1月的文檔做了metrics類型為max的處理后,結果在此"value" : 80000.0 ---2014年1月的文檔中,price字段的最大值},"min_price" : { ---2014年1月的文檔做了metrics類型為min的處理后,結果在此"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 連續多次聚合

連續分桶,第二次分桶一定是在第一次分桶的基礎上,對每一個桶再進行二次分桶,這一點可以在{}范圍上看出,global關鍵字可以突破這個限制,但是兩次分桶的結果仍然遵循{}的層次,這一點可以在全局桶體會到。

  • 來做一個略為復雜的聚合操作:按季度展示每個汽車品牌的銷售總額;
  • 操作的第一步是按照時間區間做聚合,然后在每個桶中,將文檔按照品牌做第二次聚合,第二次聚合的結果也可以理解為多個桶,每個桶中的文檔,是某個平臺在某個季度的銷售總額;
# 可執行 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對象為空"aggs": { ---聚合命令"sales": { ---聚合字段名稱"date_histogram": { ---桶類型為時間區間"field": "sold", ---指定sold字段的值作為判斷條件"interval": "1q", ---區間間隔為1季度"format": "yyyy-MM-dd", ---返回的桶的key,被格式化時的格式"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" : [ ---聚合結果{"key_as_string" : "2014-01-01", ---當前桶的key的格式化后的值"key" : 1388534400000, ---當前桶的key原值"doc_count" : 2, ---當前桶中文檔數"per_make_sum" : { ---第二層桶的名稱"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [ ---第二層聚合結果{"key" : "bmw", ---聚合字段的值,這里是汽車品牌"doc_count" : 1, ---桶內的文檔數量"sum_price" : { ---metrics處理結果名稱"value" : 80000.0 ---metrics處理結果,這里是銷售額累加值}},{"key" : "ford", ---聚合字段的值,這里是汽車品牌"doc_count" : 1, ---桶內的文檔數量"sum_price" : { ---metrics處理結果名稱"value" : 25000.0 ---metrics處理結果,這里是銷售額累加值

1.3 范圍限定

1.3.1 最簡單的查詢范圍

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

# 可執行 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" : { ---聚合結果"popular_colors" : { ---聚合字段"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [ ---這個數組的元素是所有的桶{"key" : "blue", ---color為blue的文檔"doc_count" : 1 ---文檔數為1},{"key" : "green", ---color為blue的文檔"doc_count" : 1 ---文檔數為1}]}} }

1.3.2 全局桶

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

# 可執行 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": { ---直接對范圍內的所有文檔執行metrics,類型是累加"field": "price" ---選擇price字段的值進行累加}},"all": { ---聚合字段名"global": {}, ---全局桶關鍵字,表示忽略前面term查詢的范圍限定"aggs": { ---聚合"all_sales": { ---聚合字段名"sum": { ---直接對范圍內的所有文檔執行metrics,類型是累加"field": "price" ---選擇price字段的值進行累加}}}}} } # es返回 ......"aggregations" : { ---聚合結果"all" : { ---全局桶的聚合結果(term查詢無效)"doc_count" : 8, ---文檔總數"all_sales" : { ---聚合字段名"value" : 212000.0 ---總銷售額}},"ford_sales" : { ---聚合字段名(term查詢限定了范圍,只有福特汽車的銷售記錄)"value" : 55000.0 ---福特汽車銷售額}} }

1.3.3 使用filter提高查詢性能

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

# 可執行 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": { ---聚合結果"ford_sales": { ---聚合字段名"sum": { ---metrics操作,累加"field": "price" ---累加字段是price}},"all": { ---聚合字段名 "global": {}, ---全局桶關鍵字,表示忽略范圍限定"aggs": { ---聚合"all_sales": { ---聚合字段名"sum": { ---metrics操作,累加"field": "price" ---累加字段是price}}}}} }

1.3.4 桶內filter

學習桶內filter之前,先看看官方的布爾查詢DSL,如下所示,查詢JSON對象的內部可以加入filter,對查詢結果做過濾:

GET /_search {"query": { "bool": { "must": [ ---布爾查詢{ "match": { "title": "Search" }}, { "match": { "content": "Elasticsearch" }} ],"filter": [ ---對查詢結果做過濾{ "term": { "status": "published" }}, { "range": { "publish_date": { "gte": "2015-01-01" }}} ]}} }
  • 桶內filter和布爾查詢中的filter類似,對進入桶中的數據可以加入filter,這樣桶內的數據就是此filter過濾后的數據了;
  • 舉個例子,統計藍色的福特汽車銷售額,首先限定品牌范圍,這個可以直接用之前的限定方式,然后在桶內加入一個filter,只保留顏色為藍色的文檔:
GET /cars/transactions/_search {"size": 0,"query": {"bool": { ---布爾查詢,里面可以將query和filter組合使用"filter": { ---本例只用到了filter"term": { ---精確匹配"make": "ford" ---匹配福特品牌 }}}},"aggs": {"sales": {"filter": { ---桶內filter"term": { ---精確匹配"color": "blue" ---匹配藍色}},"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 結果排序

1.4.1 默認排序

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

1.4.2 內置排序

除了自定義排序,es自身也內置了兩種排序參數,可以直接拿來使用:

# _count:這個參數對應的就是doc_count,以下請求的排序效果和默認的排序效果是一致 GET /cars/transactions/_search {"size":0,"aggs":{"popular_colors":{"terms": {"field": "color","order": { ---表示要對聚合結果做排序"_count": "desc" ---排序字段是doc_count,順序是降序}}} } }# _key:在區間聚合的時候(histogram或者date_histogram),可以根據桶的key做排序: GET /cars/transactions/_search {"size": 0,"aggs": {"price": {"histogram": { ---區間聚合"field": "price", ---取price字段的值"interval": 20000, ---每個區間的大小是20000"order": { ---表示要對聚合結果做排序"_key": "desc" ---排序字段是桶的key值,這里是每個區間的起始值,順序是降序}}}} } # 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 一個官網例子

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:

# 可執行 # 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 詳細講解了聚合查詢
  • https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-nested-aggregation.html官網例子
  • 總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。