聚合
類似於 DSL 查詢表達式,聚合也有 可組合 的語法:獨立單元的功能可以被混合起來提供你需要的自定義行爲。這意味着只需要學習很少的基本概念,就可以得到幾乎無盡的組合。
要掌握聚合,你只需要明白兩個主要的概念:
桶(Buckets)
滿足特定條件的文檔的集合
指標(Metrics)
對桶內的文檔進行統計計算
這就是全部了!每個聚合都是一個或者多個桶和零個或者多個指標的組合。翻譯成粗略的SQL語句來解釋吧:
SELECT COUNT(color)
FROM table
GROUP BY color
COUNT(color) 相當於指標。GROUP BY color 相當於桶。
桶在概念上類似於 SQL 的分組(GROUP BY),而指標則類似於 COUNT() 、 SUM() 、 MAX() 等統計方法。
聚合結構
"aggregations" : { "<aggregation_name>" : { "<aggregation_type>" : { <aggregation_body> } [,"meta" : { [<meta_data_body>] } ]? [,"aggregations" : { [<sub_aggregation>]+ } ]? } [,"<aggregation_name_2>" : { ... } ]* }
可以縮寫
"aggs" : { "<聚合的名稱>" : { "<aggregation_type>" : { <aggregation_body> } [,"meta" : { [<meta_data_body>] } ]? [,"aggregations" : { [<sub_aggregation>]+ } ]? } [,"<聚合的名稱_2>" : { ... } ]* }
單值聚合
一個簡單平均數的例子:
POST /exams/_bulk { "index": {}} { "grade" : 100, "name" : "張三" } { "index": {}} { "grade" : 50, "name" : "李四" } { "index": {}} { "grade" : 60, "name" : "王五" }
查詢平均分:
這是單值聚合,並沒有group by的作用:
POST /exams/_search?size=0 { "aggs" : { "avg_grade" : { "avg" : { "field" : "grade" } } } }
結果:
"hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : null, "hits" : [ ] }, "aggregations" : { "avg_grade" : { "value" : 70.0 } }
缺失補值
例:錄入一些缺少了分數的記錄
POST /exams/_bulk { "index": {}} { "name" : "劉七" } { "index": {}} { "name" : "趙八" }
missing語句的含義是缺值按指定值補上(即50分)
POST /exams/_search?size=0 { "aggs" : { "grade_avg" : { "avg" : { "field" : "grade", "missing": 50 } } } }
結果如下:
"hits" : { "total" : { "value" : 5, "relation" : "eq" }, "max_score" : null, "hits" : [ ] }, "aggregations" : { "grade_avg" : { "value" : 62.0 } }
基數聚合 Cardinality Aggregationedit
用途在於快速計數的統計,有點像Redis裏的基數計算,聚合查詢存在誤差,在5%範圍之內。
POST /products/_bulk { "index": {}} { "type" : 1, "name" : "書1" } { "index": {}} { "type" : 1, "name" : "書2" } { "index": {}} { "type" : 1, "name" : "書3" } { "index": {}} { "type" : 2, "name" : "食物1" } { "index": {}} { "type" : 1, "name" : "書4" } { "index": {}} { "type" : 1, "name" : "食物2" }
聚合:
POST /products/_search?size=0 { "aggs" : { "type_count" : { "cardinality" : { "field" : "type" } } } }
結果:
"aggregations" : { "type_count" : { "value" : 2 } }
注意,類型是存在2種。所以查出有2種產品。
擴展狀態統計Extended Stats Aggregationedit
擴展的統計數據聚合是統計數據聚合的擴展版本,其中添加了額外的度量,如平方和、方差、標準偏差和標準偏差界限。
{ "size": 0, "aggs" : { "grades_stats" : { "extended_stats" : { "field" : "grade", "missing": 50 } } } }
結果:
"hits" : { "total" : { "value" : 5, "relation" : "eq" }, "max_score" : null, "hits" : [ ] }, "aggregations" : { "grades_stats" : { "count" : 5, "min" : 50.0, "max" : 100.0, "avg" : 62.0, "sum" : 310.0, "sum_of_squares" : 21100.0, "variance" : 376.0, "std_deviation" : 19.390719429665317, "std_deviation_bounds" : { "upper" : 100.78143885933063, "lower" : 23.218561140669365 } }
最大最小值
POST /sales/_search?size=0 { "aggs" : { "min_price" : { "min" : { "field" : "price" } } } }
百分位數聚合Percentiles Aggregation
這是一種多值度量聚合,計算從聚合文檔中提取的數值上的一個或多個百分位數。這些值可以從文檔中的特定數字字段中提取,也可以由提供的腳本生成。
百分位數表示觀察值的某個百分比出現的點。例如,95%是大於觀察值95%的值,即最好的5%的數據值。百分位數通常用於查找異常值。在正態分佈中,0.13%和99.87%代表三個與平均值的標準差。任何超出三個標準差的數據通常被視爲異常。
當一系列的百分位數被檢索到時,它們可以用來估計數據分佈,並確定數據是否是傾斜的、雙峯的等。
增加一些數據:
POST /exams/_bulk { "index": {}} { "grade" : 88, "name" : "a" } { "index": {}} { "grade" : 97, "name" : "b" } { "index": {}} { "grade" : 82, "name" : "c" } { "index": {}} { "grade" : 79, "name" : "d" } { "index": {}} { "grade" : 66, "name" : "e" } { "index": {}} { "grade" : 85, "name" : "f" }
聚合:
GET exams/_search { "size": 0, "aggs" : { "load_time_outlier" : { "percentiles" : { "field" : "grade" , "missing": 75 } } } }
結果
"aggregations" : { "load_time_outlier" : { "values" : { "1.0" : 50.0, "5.0" : 50.5, "25.0" : 68.25, "50.0" : 79.0, "75.0" : 87.25, "95.0" : 99.85, "99.0" : 100.0 } }
結論:99.85分以上就是5%最好的分數,考了79分以上就能力壓50%的同學了,68.25 - 87.25 是正態分佈最多的分數。
百分位等級聚合Percentile Ranks Aggregation
一種多值度量聚合,它計算多個百分位數,高於從聚合文檔中提取的數值。這些值可以從文檔中的特定數字字段中提取,也可以由提供的腳本生成。
比如想知道95分到100分在百分位的位置,可以用以下語句:
GET exams/_search { "size": 0, "aggs" : { "load_time_ranks" : { "percentile_ranks" : { "field" : "grade", "values" : [95, 100], "missing": 75 } } } }
結果:
95分超越了85.6的同學,100分就是最高分。
"aggregations" : { "load_time_ranks" : { "values" : { "95.0" : 85.6060606060606, "100.0" : 100.0 } }
統計聚合 Stats Aggregation
包含:
min, max, sum, count and avg.
POST /exams/_search?size=0 { "aggs" : { "grades_stats" : { "stats" : { "field" : "grade" } } } }
結果
"hits" : { "total" : { "value" : 11, "relation" : "eq" }, "max_score" : null, "hits" : [ ] }, "aggregations" : { "grades_stats" : { "count" : 9, "min" : 50.0, "max" : 100.0, "avg" : 78.55555555555556, "sum" : 707.0 } }
合計聚合Sum Aggregation
一個單值度量聚合,它彙總從聚合文檔中提取的數值。這些值可以從文檔中的特定數字字段中提取,也可以由提供的腳本生成。
假設數據由代表銷售記錄的文檔組成,我們可以將所有帽子的銷售價格加起來,得出合計。
如果寫成SQL,就是 select sum(price) from sales where type = 'hat' group by type
數據:
POST /sales/_bulk { "index": {}} { "price" : 88, "name" : "a", "type" : "hat" } { "index": {}} { "price" : 97, "name" : "b", "type" : "hat" } { "index": {}} { "price" : 82, "name" : "c", "type" : "cloth" } { "index": {}} { "price" : 102, "name" : "c", "type" : "cloth" }
聚合:
POST /sales/_search?size=0 { "query" : { "constant_score" : { "filter" : { "match" : { "type" : "hat" } } } }, "aggs" : { "hat_prices" : { "sum" : { "field" : "price" } } } }
結果
"aggregations" : { "hat_prices" : { "value" : 185.0 } }
平均值+過濾
POST /sales/_search?size=0 { "aggs" : { "t_shirts" : { "filter" : { "term": { "type": "hat" } }, "aggs" : { "avg_price" : { "avg" : { "field" : "price" } } } } } }
top_hits聚合
top_hits聚合器可以有效地用於通過bucket聚合器按特定字段對結果集進行分組。一個或多個bucket聚合器確定結果集被切片到的屬性。
有點類似SQL語言的top + order by
POST /product/_bulk { "index": {}} { "type" : 1, "id" : 1, "price" : 5 } { "index": {}} { "type" : 1, "id" : 2, "price" : 15 } { "index": {}} { "type" : 1, "id" : 3, "price" : 40 } { "index": {}} { "type" : 1, "id" : 4, "price" : 29 } { "index": {}} { "type" : 1, "id" : 5, "price" : 50 } { "index": {}} { "type" : 2, "id" : 6, "price" : 100 } { "index": {}} { "type" : 3, "id" : 7, "price" : 50 } { "index": {}} { "type" : 3, "id" : 8, "price" : 60 } { "index": {}} { "type" : 3, "id" : 9, "price" : 108 } { "index": {}} { "type" : 3, "id" : 10, "price" : 65 }
查詢不同類型的最前的一條記錄(通過id排序),順序爲asc,倒序爲desc
POST /product/_search?size=0 { "aggs": { "top_tags": { "terms": { "field": "type", "size": 2 }, "aggs": { "top_sales_hits": { "top_hits": { "sort": [ { "id": { "order": "asc" } } ], "_source": { "includes": [ "id", "price" ] }, "size" : 1 } } } } } }
結果
"aggregations" : { "top_tags" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 1, "buckets" : [ { "key" : 1, "doc_count" : 5, "top_sales_hits" : { "hits" : { "total" : { "value" : 5, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "product", "_type" : "_doc", "_id" : "uL-3nW8BdESjTDDp3t4v", "_score" : null, "_source" : { "price" : 5, "id" : 1 }, "sort" : [ 1 ] } ] } } }, { "key" : 3, "doc_count" : 4, "top_sales_hits" : { "hits" : { "total" : { "value" : 4, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "product", "_type" : "_doc", "_id" : "vr-3nW8BdESjTDDp3t4v", "_score" : null, "_source" : { "price" : 50, "id" : 7 }, "sort" : [ 7 ] } ] } } }
值計數聚合 Value Count Aggregation
通常,此聚合器將與其他單值聚合一起使用。例如,當計算平均值時,一個人可能對計算平均值所依據的值的數量感興趣。
POST /product/_search?size=0 { "aggs" : { "types_count" : { "value_count" : { "field" : "type" } } } }
計算type不爲空的總條數爲多少,可以看到之前的例子就是10條記錄
"hits" : { "total" : { "value" : 10, "relation" : "eq" }, "max_score" : null, "hits" : [ ] }, "aggregations" : { "types_count" : { "value" : 10 } }
中位數絕對偏差彙總 Median Absolute Deviation Aggregation
該單值聚集接近其搜索結果的中值絕對偏差。
中位數絕對偏差是可變性的度量。它是一個穩健的統計,這意味着它對於描述可能有異常值或可能不是正態分佈的數據是有用的。對於這些數據,它可以比標準差更具描述性。
它被計算爲每個數據點偏離整個樣本中值的中值。也就是說,對於隨機變量X,
MAD=median(∣X i−median(X)∣)
考慮數據集(1, 1, 2, 2, 4, 6, 9),它的中位數爲2。數據點到2的絕對偏差爲(1, 1, 0, 0, 2, 4, 7),該偏差列表的中位數爲1(因爲排序後的絕對偏差爲(0, 0, 1, 1, 2, 4, 7))。所以該數據的絕對中位差爲1。絕對中位差是一種統計離差的測量。而且,MAD是一種魯棒統計量,比標準差更能適應數據集中的異常值。對於標準差,使用的是數據到均值的距離平方,所以大的偏差權重更大,異常值對結果也會產生重要影響。對於MAD,少量的異常值不會影響最終的結果。由於MAD是一個比樣本方差或者標準差更魯棒的度量,它對於不存在均值或者方差的分佈效果更好,比如柯西分佈。
GET /product/_search { "size": 0, "aggs": { "price_average": { "avg": { "field": "price" } }, "review_variability": { "median_absolute_deviation": { "field": "price" } } } }
可以看到結果,平均數是52.2,中位數偏差18,偏差有點大。
"aggregations" : { "price_average" : { "value" : 52.2 }, "review_variability" : { "value" : 18.0 } }