(六)ElasticSearch 6.1.1聚合查询
1 普通類型
1.1 基本操作
1.1.1 導入實戰數據
數據字段如下:
| price | long | 汽車售價 |
| color | text | 汽車顏色 |
| make | text | 汽車品牌 |
| sold | date | 銷售日期 |
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)等,接下來試試累加和的用法;
- 下面請求的作用是統計每種顏色汽車的銷售總額:
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桶的用法:每月銷售多少臺汽車:
1.2.5 連續多次聚合
連續分桶,第二次分桶一定是在第一次分桶的基礎上,對每一個桶再進行二次分桶,這一點可以在{}范圍上看出,global關鍵字可以突破這個限制,但是兩次分桶的結果仍然遵循{}的層次,這一點可以在全局桶體會到。
- 來做一個略為復雜的聚合操作:按季度展示每個汽車品牌的銷售總額;
- 操作的第一步是按照時間區間做聚合,然后在每個桶中,將文檔按照品牌做第二次聚合,第二次聚合的結果也可以理解為多個桶,每個桶中的文檔,是某個平臺在某個季度的銷售總額;
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,其實適用于查詢的過濾器也能應用在聚合操作中,下面是過濾+聚合的查詢,和前面一樣,也是統計總銷售和和福特汽車的銷售額:
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,只保留顏色為藍色的文檔:
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:
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}參考資料
總結
以上是生活随笔為你收集整理的(六)ElasticSearch 6.1.1聚合查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: xss防御补丁_Discuz论坛最新do
- 下一篇: iso是什么意思/iso9001质量管理