简介
目前在官方文档有4种聚合(Aggregations )方式分别是:
Metric (指标聚合):
最常用的聚合方式例如 平均值,求和等等
Bucketing (桶聚合):
就是常说的分组聚合
- Matrix (矩阵聚合) :
在多个字段上操作并根据从请求的文档字段提取的值生成矩阵结果的聚合族。与度量聚合和桶聚合不同,此聚合族尚不支持脚本。
- Pipeline (管道聚合):
由于每个 bucket 有效地定义了一个文档集(属于 bucket 的所有文档) ,因此可以潜在地在 bucket 级别上关联聚合,并且这些聚合将在 bucket 的上下文中执行。这就是聚合的真正威力所在: 聚合可以被嵌套!
方法 / 步骤
一: 简介并加入测试数据
1.1 聚合相关参数
指标聚合有参数有:range / date_range / terms / histogram / date_histogram / ...
聚合类型 | 聚合参数 | 简介 |
---|---|---|
Bucketing | Range Aggregation | - 范围聚合查询 |
Bucketing | Date Range Aggregation | - 时间范围聚合查询 |
Bucketing | Terms Aggregation | - 分组统计 |
Bucketing | Histogram Aggregation | - 直方图统计 |
Bucketing | Date histogram aggregation | - 时间直方图统计 |
1.2 DSL 查询格式
"aggregations" : {
"<aggregation_name>" : {
"<aggregation_type>" : {
<aggregation_body>
}
[,"meta" : { [<meta_data_body>] } ]?
[,"aggregations" : { [<sub_aggregation>]+ } ]?
}
[,"<aggregation_name_2>" : { ... } ]*
}
1.3 插入批量测试数据
POST /staff/_bulk
{"index":{"_id":1}}
{"name":"zs","realname":"张三","age":10,"birthday":"2018-12-27","salary":1000.0,"address":"北京市北海公园"}
{"index":{"_id":2}}
{"name":"ls","realname":"李四","age":20,"birthday":"2017-10-20","salary":2000.0,"address":"北京市京东大峡谷"}
{"index":{"_id":3}}
{"name":"ww","realname":"王五","age":30,"birthday":"2016-03-15","salary":3000.0,"address":"北京市陶然亭"}
{"index":{"_id":4}}
{"name":"zl","realname":"赵六","age":40,"birthday":"2003-04-19","salary":4000.0,"address":"北京市玉渊潭"}
{"index":{"_id":5}}
{"name":"tq","realname":"田七","age":50,"birthday":"2001-08-11","salary":5000.0,"address":"北京市圆明园"}
插入完成后,查看索引数据:
GET /staff/_search
二: 常规查询
2.1 Range Aggregation / 返回聚合
每个范围表示一个桶。在聚合过程中,将根据每个bucket范围和相关/匹配文档的“bucket”检查从每个文档提取的值。
如: 统计0-20岁,20-40岁,40~60岁各个区间段的用户人数
POST /staff/_search
{
"aggs": {
"age_ranges_count": {
"range": {
"field": "age",
"ranges": [
{
"from": 0,
"to": 20
},
{
"from": 20,
"to": 40
},
{
"from": 40,
"to": 60
}
]
}
}
}
}
- 返回内容
.....
"aggregations" : {
"age_ranges_count" : {
"buckets" : [
{
"key" : "0.0-20.0",
"from" : 0.0,
"to" : 20.0,
"doc_count" : 1
},
{
"key" : "20.0-40.0",
"from" : 20.0,
"to" : 40.0,
"doc_count" : 2
},
{
"key" : "40.0-60.0",
"from" : 40.0,
"to" : 60.0,
"doc_count" : 2
}
]
}
}
.....
- 如果第一个区间开始值和最后一个区间结束值不想指定的话,可以不用写from和to,如下:
POST /staff/_search
{
"aggs": {
"age_ranges_count": {
"range": {
"field": "age",
"ranges": [
{
"to": 20
},
{
"from": 20,
"to": 40
},
{
"from": 40,
"to": 60
}
]
}
}
}
}
- 返回内容
....
"aggregations" : {
"age_ranges_count" : {
"buckets" : [
{
"key" : "*-20.0",
"to" : 20.0,
"doc_count" : 1
},
{
"key" : "20.0-40.0",
"from" : 20.0,
"to" : 40.0,
"doc_count" : 2
},
{
"key" : "40.0-60.0",
"from" : 40.0,
"to" : 60.0,
"doc_count" : 2
}
]
}
}
....
2.2 Date Range Aggregation / 时间范围聚合
此聚合与Range Aggregation常规范围聚合的主要区别在于,可以用日期数学表达式表示from和to值,而且还可以指定返回from和to响应字段的日期格式。注意,此聚合包含每个范围的from值并排除to值。
- now+10y:表示从现在开始的第10年。
- now+10M:表示从现在开始的第10个月。
- 1990-01-10||+20y:表示从1990-01-01开始后的第20年,即2010-01-01。
- now/y:表示在年位上做舍入运算。
如: 统计生日在2017年、2018年、2019年的用户
now/y:当前年的1月1日
now:当前时间
now/y-1y:当前年上一年的1月1日
POST /staff/_search
{
"aggs": {
"birthday_count": {
"date_range": {
"field": "birthday",
"format": "yyyy-MM-dd",
"ranges": [
{
"from": "now/y-1y",
"to": "now/y"
},
{
"from": "now/y-2y",
"to": "now/y-1y"
},
{
"from": "now/y-3y",
"to": "now/y-2y"
}
]
}
}
}
}
- 返回数据
"aggregations" : {
"birthday_count" : {
"buckets" : [
{
"key" : "2019-01-01-2020-01-01",
"from" : 1.5463008E12,
"from_as_string" : "2019-01-01",
"to" : 1.5778368E12,
"to_as_string" : "2020-01-01",
"doc_count" : 0
},
{
"key" : "2020-01-01-2021-01-01",
"from" : 1.5778368E12,
"from_as_string" : "2020-01-01",
"to" : 1.6094592E12,
"to_as_string" : "2021-01-01",
"doc_count" : 0
},
{
"key" : "2021-01-01-2022-01-01",
"from" : 1.6094592E12,
"from_as_string" : "2021-01-01",
"to" : 1.6409952E12,
"to_as_string" : "2022-01-01",
"doc_count" : 0
}
]
}
}
2.3 Terms Aggregation / 分组聚合
- 对年龄进行聚合,显示3条数据
POST /staff/_search
{
"aggs": {
"age_count": {
"terms": {
"field": "age",
"size": 3
}
}
}
}
- 聚合结果
key年龄 为10,20 ,30各为一条
......
"aggregations" : {
"age_count" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 2,
"buckets" : [
{
"key" : 10,
"doc_count" : 1
},
{
"key" : 20,
"doc_count" : 1
},
{
"key" : 30,
"doc_count" : 1
}
]
}
}
......
2.4 Histogram Aggregation / 直方图聚合
它与前面介绍的Range聚合非常像,只不过Range可以任意划分区间,而Histogram做等间距划分。既然是等间距划分,那么参数里面必然有距离参数,就是interval参数。
如:根据年龄间隔(20岁)统计各个年龄段的员工总人数
POST /staff/_search?size=0
{
"aggs": {
"salary_value_count": {
"value_count": {
"field": "salary"
}
}
}
}
- 返回结果
.....
"aggregations" : {
"age_histogram_count" : {
"buckets" : [
{
"key" : 0.0,
"doc_count" : 1
},
{
"key" : 20.0,
"doc_count" : 2
},
{
"key" : 40.0,
"doc_count" : 2
}
]
}
}
.....
2.5 Date histogram aggregation / 时间直方图聚合
日期直方图聚合,专门对时间类型的字段做直方图聚合。这种需求是比较常用见得的,我们在统计时,通常就会按照固定的时间断(1个月或1年等)来做统计
如:按年统计用户生日的总人数
POST /staff/_search
{
"aggs": {
"birthday_data_histogram_count": {
"date_histogram": {
"field": "birthday",
"interval": "year",
"format": "yyyy-MM-dd"
}
}
}
}
- 返回结果
.....
"aggregations" : {
"birthday_data_histogram_count" : {
"buckets" : [
{
"key_as_string" : "2001-01-01",
"key" : 978307200000,
"doc_count" : 1
},
{
"key_as_string" : "2002-01-01",
"key" : 1009843200000,
"doc_count" : 0
},
{
"key_as_string" : "2003-01-01",
"key" : 1041379200000,
"doc_count" : 1
},
{
"key_as_string" : "2004-01-01",
"key" : 1072915200000,
"doc_count" : 0
},
{
"key_as_string" : "2005-01-01",
"key" : 1104537600000,
"doc_count" : 0
},
{
"key_as_string" : "2006-01-01",
"key" : 1136073600000,
"doc_count" : 0
},
{
"key_as_string" : "2007-01-01",
"key" : 1167609600000,
"doc_count" : 0
},
{
"key_as_string" : "2008-01-01",
"key" : 1199145600000,
"doc_count" : 0
},
{
"key_as_string" : "2009-01-01",
"key" : 1230768000000,
"doc_count" : 0
},
{
"key_as_string" : "2010-01-01",
"key" : 1262304000000,
"doc_count" : 0
},
{
"key_as_string" : "2011-01-01",
"key" : 1293840000000,
"doc_count" : 0
},
{
"key_as_string" : "2012-01-01",
"key" : 1325376000000,
"doc_count" : 0
},
{
"key_as_string" : "2013-01-01",
"key" : 1356998400000,
"doc_count" : 0
},
{
"key_as_string" : "2014-01-01",
"key" : 1388534400000,
"doc_count" : 0
},
{
"key_as_string" : "2015-01-01",
"key" : 1420070400000,
"doc_count" : 0
},
{
"key_as_string" : "2016-01-01",
"key" : 1451606400000,
"doc_count" : 1
},
{
"key_as_string" : "2017-01-01",
"key" : 1483228800000,
"doc_count" : 1
},
{
"key_as_string" : "2018-01-01",
"key" : 1514764800000,
"doc_count" : 1
}
]
}
}
.....
三: 聚合查询嵌套使用
通过嵌套,可以使得metric类型的聚合操作作用在每一bucket上。我们可以使用ES的嵌套聚合操作来完成稍微复杂一点的统计功能。
3.1 统计每年中用户的最高工资
POST /staff/_search
{
"aggs": {
"birthday_data_histogram_count": {
"date_histogram": {
"field": "birthday",
"interval": "year",
"format": "yyyy-MM-dd"
},
"aggs": {
"max_salary": {
"max": {
"field": "salary"
}
}
}
}
}
}
- 返回结果
.....
"aggregations" : {
"birthday_data_histogram_count" : {
"buckets" : [
{
"key_as_string" : "2001-01-01",
"key" : 978307200000,
"doc_count" : 1,
"max_salary" : {
"value" : 5000.0
}
},
{
"key_as_string" : "2002-01-01",
"key" : 1009843200000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2003-01-01",
"key" : 1041379200000,
"doc_count" : 1,
"max_salary" : {
"value" : 4000.0
}
},
{
"key_as_string" : "2004-01-01",
"key" : 1072915200000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2005-01-01",
"key" : 1104537600000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2006-01-01",
"key" : 1136073600000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2007-01-01",
"key" : 1167609600000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2008-01-01",
"key" : 1199145600000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2009-01-01",
"key" : 1230768000000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2010-01-01",
"key" : 1262304000000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2011-01-01",
"key" : 1293840000000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2012-01-01",
"key" : 1325376000000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2013-01-01",
"key" : 1356998400000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2014-01-01",
"key" : 1388534400000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2015-01-01",
"key" : 1420070400000,
"doc_count" : 0,
"max_salary" : {
"value" : null
}
},
{
"key_as_string" : "2016-01-01",
"key" : 1451606400000,
"doc_count" : 1,
"max_salary" : {
"value" : 3000.0
}
},
{
"key_as_string" : "2017-01-01",
"key" : 1483228800000,
"doc_count" : 1,
"max_salary" : {
"value" : 2000.0
}
},
{
"key_as_string" : "2018-01-01",
"key" : 1514764800000,
"doc_count" : 1,
"max_salary" : {
"value" : 1000.0
}
}
]
}
}
.....
先通过date_histogram按照年分组,然后再通过嵌套max聚合查询统计出每年最高工资是多少。
3.2 求每个年龄区间段的工资总和
....
"aggregations" : {
"age_ranges_count" : {
"buckets" : [
{
"key" : "0.0-20.0",
"from" : 0.0,
"to" : 20.0,
"doc_count" : 1,
"sum_salary" : {
"value" : 1000.0
}
},
{
"key" : "20.0-40.0",
"from" : 20.0,
"to" : 40.0,
"doc_count" : 2,
"sum_salary" : {
"value" : 5000.0
}
},
{
"key" : "40.0-60.0",
"from" : 40.0,
"to" : 60.0,
"doc_count" : 2,
"sum_salary" : {
"value" : 9000.0
}
}
]
}
}
....