ElasticSearch 聚合
一、聚合概念
聚合类似于 DSL 查询表达式, 聚合也有 可组合 的语法:独立单元的功能可以被混合起来提供你需要的自定义行为,你只需要明白两个主要的概念:
- 桶(Buckets)
- 满足特定条件的文档的集合
- 指标(Metrics)
- 对桶内的文档进行统计计算
每个聚合都是一个或者多个桶和零个或者多个指标的组合。类似于以下SQL语句:
SELECT COUNT(color)
FROM table
GROUP BY color
OUNT(color) 相当于指标,GROUP BY color 相当于桶。
桶在概念上类似于 SQL 的分组(GROUP BY),而指标则类似于 COUNT()
、 SUM()
、 MAX()
等统计方法。
二、聚合入门
1、先看一个例子。我们将会创建一些对汽车经销商有用的聚合,数据是关于汽车交易的信息:车型、制造商、售价、何时被出售等。
首先我们批量索引一些数据:
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" }
开始构建我们的第一个聚合。汽车经销商可能会想知道哪个颜色的汽车销量最好,用聚合可以轻易得到结果,用 terms
桶操作:
GET /cars/transactions/_search { "size" : 0, "aggs" : { #聚合操作被置于顶层参数aggs
之下(如果你愿意,完整形式aggregations
同样有效)。 "popular_colors" : { #为聚合指定一个我们想要名称 "terms" : { #定义单个桶的类型terms
"field" : "color" } } } }
查看结果:
{ ... "hits": {#因为我们设置了size
参数,所以不会有 hits 搜索结果返回。 "hits": [] }, "aggregations": { "popular_colors": { #popular_colors
聚合是作为aggregations
字段的一部分被返回的。 "buckets": [ { "key": "red", #每个桶的key
都与color
字段里找到的唯一词对应。它总会包含doc_count
字段,告诉我们包含该词项的文档数量。 "doc_count": 4 #每个桶的数量代表该颜色的文档数量 }, { "key": "blue", "doc_count": 2 }, { "key": "green", "doc_count": 2 } ] } } }
上面的例子告诉我们每个桶里面的文档数量,这很有用。 但通常,我们的应用需要提供更复杂的文档度量。 例如,每种颜色汽车的平均价格是多少?
为了获取更多信息,我们需要告诉 Elasticsearch 使用哪个字段,计算何种度量。 这需要将度量 嵌套 在桶内, 度量会基于桶内的文档计算统计结果。
GET /cars/transactions/_search { "size" : 0, "aggs": { "colors": { "terms": { "field": "color" }, "aggs": { # 为度量新增aggs
层。 "avg_price": { #为度量指定名字:avg_price
"avg": { "field": "price" #为price
字段定义avg
度量 } } } } } }
返回结果
{ ... "aggregations": { "colors": { "buckets": [ { "key": "red", "doc_count": 4, "avg_price": { "value": 32500 } }, { "key": "blue", "doc_count": 2, "avg_price": { "value": 20000 } }, { "key": "green", "doc_count": 2, "avg_price": { "value": 21000 } } ] } } ... }
在我们使用不同的嵌套方案时,聚合的力量才能真正得以显现。 在前例中,我们已经看到如何将一个度量嵌入桶中,它的功能已经十分强大了。
但真正令人激动的分析来自于将桶嵌套进 另外一个桶 所能得到的结果。 现在,我们想知道每个颜色的汽车制造商的分布:
GET /cars/transactions/_search { "size" : 0, "aggs": { "colors": { "terms": { "field": "color" }, "aggs": { "avg_price": { "avg": { "field": "price" } }, "make": { # 另一个聚合make
被加入到了color
颜色桶中 "terms": {#这个聚合是 terms 桶,它会为每个汽车制造商生成唯一的桶。
"field": "make"
}
}
}
}
}
}
新增的这个 make
聚合,它是一个 terms
桶(嵌套在 colors
、terms
桶内)。这意味着它 会为数据集中的每个唯一组合生成( color
、 make
)元组。
让我们看看返回的响应(为了简单我们只显示部分结果):
{ ... "aggregations": { "colors": { "buckets": [ { "key": "red", "doc_count": 4, "make": { #新的聚合嵌入在每个颜色桶中 "buckets": [ { "key": "honda", #不同制造商分解的每种颜色下车辆信息 "doc_count": 3 }, { "key": "bmw", "doc_count": 1 } ] }, "avg_price": { "value": 32500 } }, ... }
响应结果告诉我们以下几点:
- 红色车有四辆。
- 红色车的平均售价是 $32,500 美元。
- 其中三辆是 Honda 本田制造,一辆是 BMW 宝马制造