前言
本文基于官方文檔,梳理出聚合的以下幾個核心問題,目的:将Elasticsearch的聚合結合實際場景說透。
1、Elasticsearch聚合最直覺展示
差別于反向索引的key value的全文檢索,聚合兩個示例如下:
如下圖,是基于某特定分類的聚合統計結果。

如下圖:是基于月份的聚合統計結果。
2、Elasticsearch聚合定義
聚合有助于基于搜尋查詢提供聚合資料。 它基于稱為聚合的簡單建構塊,可以組合以建構複雜的資料。
基本文法結構如下:
"aggregations" : {
"<aggregation_name>" : {
"<aggregation_type>" : {
<aggregation_body>
}
[,"meta" : { [<meta_data_body>] } ]?
[,"aggregations" : { [<sub_aggregation>]+ } ]?
}
[,"<aggregation_name_2>" : { ... } ]*
}
3、Elasticsearch聚合分類
分類1:Metric聚合
基于一組文檔進行聚合。所有的文檔在一個檢索集合裡,文檔被分成邏輯的分組。
類比Mysql中的: MIN(), MAX(), STDDEV(), SUM() 操作。
單值Metric
|
v
SELECT AVG(price) FROM products
多值Metric
| |
v v
SELECT MIN(price), MAX(price) FROM products
Metric聚合的DSL類比實作:
{
"aggs":{
"avg_price":{
"avg":{
"field":"price"
}
}
}
}
Metric聚合操作對比:
Aggregation | Elasticsearch | MySQL |
---|---|---|
Avg | Yes | |
Cardinality——去重唯一值 | Yes (Sample based) | Yes (Exact)——類似:distinct |
Extended Stats | StdDev bounds missing | |
Geo Bounds | for future blog post | |
Geo Centroid | ||
Max | ||
Percentiles | Complex SQL or UDF | |
Percentile Ranks | ||
Scripted | No | |
Stats | ||
Top Hits——很重要,易被忽視 | Complex | |
Value Count |
其中,Top hits子聚合用于傳回分組中Top X比對結果集,且支援通過source過濾標明字段值。
分類2:Bucketing聚合
基于檢索構成了邏輯文檔組,滿足特定規則的文檔放置到一個桶裡,每一個桶關聯一個key。
類比Mysql中的group by操作,
Mysql使用舉例:
基于size 分桶 ...、
SELECT size COUNT(*) FROM products GROUP BY size
+----------------------+
| size | COUNT(*) |
+----------------------+
| S | 123 | <--- set of rows with size = S
| M | 456 |
| ... | ... |
bucket聚合的DSL類比實作:
{
"query": {
"match": {
"title": "Beach"
}
},
"aggs": {
"by_size": {
"terms": {
"field": "size"
}
},
"by_material": {
"terms": {
"field": "material"
}
}
}
}
Bucketing聚合對比
Childen——父子文檔 | ||
Date Histogram——基于時間分桶 | ||
Date Range | ||
Filter | n/a (yes) | |
Filters | ||
Geo Distance | ||
GeoHash grid | ||
Global | ||
Histogram | ||
IPv4 Range | ||
Missing | ||
Nested | ||
Range | ||
Reverse Nested | ||
Sampler | ||
Significant Terms | ||
Terms——最常用 |
分類3:Pipeline聚合
對聚合的結果而不是原始資料集進行操作。
想象一下,你有一個日間交易的網上商店,想要了解所有産品的按照庫存日期分組的平均價格。
在SQL中你可以寫:
SELECT in_stock_since, AVG(price) FROM products GROUP BY in_stock_since。
ES使用舉例:
以下Demo實作更複雜,按月統計銷售額,并統計出月銷售額>200的資訊。
下一節詳細給出DSL,不再重複。
分類4:Matrix聚合
ES6.4官網釋義:此功能是實驗性的,可在将來的版本中完全更改或删除。
4、Elasticsearch聚合完整舉例
4.1 步驟1:動态Mapping,導入完整資料
POST _bulk
{"index":{"_index":"cars","_type":"doc","_id":"1"}}
{"name":"bmw","date":"2017-06-01", "color":"red", "price":30000}
{"index":{"_index":"cars","_type":"doc","_id":"2"}}
{"name":"bmw","date":"2017-06-30", "color":"blue", "price":50000}
{"index":{"_index":"cars","_type":"doc","_id":"3"}}
{"name":"bmw","date":"2017-08-11", "color":"red", "price":90000}
{"index":{"_index":"cars","_type":"doc","_id":"4"}}
{"name":"ford","date":"2017-07-15", "color":"red", "price":20000}
{"index":{"_index":"cars","_type":"doc","_id":"5"}}
{"name":"ford","date":"2017-07-01", "color":"blue", "price":40000}
{"index":{"_index":"cars","_type":"doc","_id":"6"}}
{"name":"bmw","date":"2017-08-01", "color":"green", "price":10000}
{"index":{"_index":"cars","_type":"doc","_id":"7"}}
{"name":"jeep","date":"2017-07-08", "color":"red", "price":110000}
{"index":{"_index":"cars","_type":"doc","_id":"8"}}
{"name":"jeep","date":"2017-08-25", "color":"red", "price":230000}
4.2 步驟2:确認Mapping
GET cars/_mapping
4.3 步驟3:Matric聚合實作
求車的平均價錢。
POST cars/_search
{
"size": 0,
"aggs": {
"avg_grade": {
"avg": {
"field": "price"
}
}
}
}
4.4 步驟4:bucket聚合與子聚合實作
按照車品牌分組,組間按照車顔色再二次分組。
POST cars/_search
{
"size": 0,
"aggs": {
"name_aggs": {
"terms": {
"field": "name.keyword"
},
"aggs": {
"color_aggs": {
"terms": {
"field": "color.keyword"
}
}
}
}
}
}
4.5 步驟5:Pipeline聚合實作
按月統計銷售額,并統計出總銷售額大于200000的月份資訊。
POST /cars/_search
{
"size": 0,
"aggs": {
"sales_per_month": {
"date_histogram": {
"field": "date",
"interval": "month"
},
"aggs": {
"total_sales": {
"sum": {
"field": "price"
}
},
"sales_bucket_filter": {
"bucket_selector": {
"buckets_path": {
"totalSales": "total_sales"
},
"script": "params.totalSales > 200000"
}
}
}
}
}
}
5、Elasticsearch聚合使用指南
認知前提:知道Elasticsearch聚合遠比Mysql中種類要多,可實作的功能點要多。
遇到聚合問題,基于4個分類,查詢對應的官網API資訊。
以最常見場景為例:
- 确定是否是分組group by 操作,如果是,使用bucket聚合中的terms聚合實作;
- 确定是否是按照時間分組操作,如果是,使用bucket聚合中date_histogram的聚合實作;
- 确定是否是分組,組間再分組操作,如果是,使用bucket聚合中terms聚合内部再terms或者内部top_hits子聚合實作;
- 确定是否是求最大值、最小值、平均值等,如果是,使用Metric聚合對應的Max, Min,AVG等聚合實作;
- 确定是否是基于聚合的結果條件進行判定後取結果,如果是,使用pipline聚合結合其他聚合綜合實作;
多嘗試,多在kibana的 dev tool部分多驗證。
參考:
1、
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html2、
http://blog.ulf-wendel.de/2016/aggregation-features-elasticsearch-vs-mysql-vs-mongodb/3、
https://elasticsearch.cn/article/629