news 2026/9/23 8:50:35

[ELK实战] Elasticsearch 聚合查询二: Bucketing/桶聚合

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[ELK实战] Elasticsearch 聚合查询二: Bucketing/桶聚合

简介

目前在官方文档有4种聚合(Aggregations )方式分别是:

  1. Metric (指标聚合):
    最常用的聚合方式例如 平均值,求和等等

  2. Bucketing (桶聚合):
    就是常说的分组聚合

  3. Matrix (矩阵聚合) :
    在多个字段上操作并根据从请求的文档字段提取的值生成矩阵结果的聚合族。与度量聚合和桶聚合不同,此聚合族尚不支持脚本。

  4. Pipeline (管道聚合):
    由于每个 bucket 有效地定义了一个文档集(属于 bucket 的所有文档) ,因此可以潜在地在 bucket 级别上关联聚合,并且这些聚合将在 bucket 的上下文中执行。这就是聚合的真正威力所在: 聚合可以被嵌套!

方法 / 步骤

一: 简介并加入测试数据

1.1 聚合相关参数

指标聚合有参数有:range / date_range / terms / histogram / date_histogram / …

聚合类型聚合参数简介
BucketingRange Aggregation- 范围聚合查询
BucketingDate Range Aggregation- 时间范围聚合查询
BucketingTerms Aggregation- 分组统计
BucketingHistogram Aggregation- 直方图统计
BucketingDate 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} }]} }....

参考资料 & 致谢

[1]官方文档
[2] ElasticSearch全文搜索引擎之Aggregation聚合查询(结合Kibana)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 8:48:16

GPU服务器存储选型:SFF与LFF硬盘抉择指南

1. GPU服务器存储选型&#xff1a;为什么SFF和LFF的抉择比你想的更重要搞GPU服务器的人&#xff0c;十有八九把注意力全砸在显卡型号、显存带宽、NVLink拓扑这些地方&#xff0c;存储嘛&#xff0c;随便塞几块盘能跑就行。我刚开始接触GPU集群的时候也是这个心态&#xff0c;直…

作者头像 李华
网站建设 2026/9/23 8:41:17

2026年9月想要办理企业微信上门服务,查看相关联系电话

企业微信作为一款企业通讯与办公工具&#xff0c;能够与微信互通&#xff0c;为企业提供内外一体的协同与客户连接能力。截至2025年3月&#xff0c;其在App Store“商务”类排名第2&#xff0c;拥有超1500万企业用户。对于希望在2026年9月办理企业微信上门服务的企业&#xff0…

作者头像 李华
网站建设 2026/9/23 8:40:55

Java环境变量配置全攻略:JAVA_HOME、Path与多JDK共存排查指南

最近后台收到好几条留言&#xff0c;都是同一个问题&#xff1a;明明照着视频一步步装了JDK&#xff0c;java -version一敲&#xff0c;屏幕却冷冷地弹出一句"java 不是内部或外部命令"。我回了一句"你环境变量配了吗"&#xff0c;对方半天憋出一句"配…

作者头像 李华
网站建设 2026/9/23 8:40:08

国产专业音响实力品牌应用场景与选型指南

在筹备一场大型演唱会或搭建专业体育场馆时&#xff0c;音响系统的选型往往决定了最终呈现效果的成败。很多项目负责人在初期容易陷入一个误区&#xff1a;只关注单一品牌的知名度&#xff0c;而忽略了不同场景下声学环境的巨大差异。实际上&#xff0c;从万人体育馆的远距离投…

作者头像 李华
网站建设 2026/9/23 8:39:37

AC-SCUC与DC-SCUC协同建模:MATLAB工程级混合求解方案

简介&#xff1a;本资源为电力系统优化方向的MATLAB实践项目&#xff0c;面向电气工程、自动化及人工智能交叉领域的研究生、科研人员与高年级本科生&#xff0c;聚焦安全约束机组组合&#xff08;SCUC&#xff09;这一核心调度问题。项目完整实现基于交流潮流方程&#xff08;…

作者头像 李华