为什么使用管道聚合:
Elasticsearch 基础聚合主要分为指标聚合和桶聚合两类,仅能实现对原始文档的分组、基础数值统计,满足常规的数据分析需求,但在复杂业务统计、时序数据复盘、指标二次计算等场景中存在明显短板。而**管道聚合(Pipeline Aggregation)**的出现,完美弥补了基础聚合的缺陷,也是我们业务开发中必须使用它的核心原因。
首先,基础聚合仅能直接扫描原始文档数据,完成单次计算,无法对聚合后的结果进行二次加工。例如我们可以通过桶聚合按天统计每日订单销售额,通过指标聚合算出单日总额,但无法直接在ES中完成累计销售额、日环比、整体均值、峰值筛选等衍生计算,传统方案只能将聚合结果返回客户端,通过代码二次处理,不仅增加接口网络传输开销、客户端计算压力,还会导致数据统计口径不统一、可视化联动性差的问题。
其次,管道聚合的核心特性是基于已有聚合结果计算,不重复扫描原始文档 ,所有衍生计算均在ES协调节点完成。它依托 buckets_path 关联上层聚合的桶数据和指标数据,实现一次查询、多层统计,大幅提升复杂数据分析的效率,减少系统资源消耗。
最后,针对时序数据统计、动态桶筛选、自定义业务指标计算等高频场景,管道聚合提供了原生能力支持。无论是时间维度的累计统计、趋势平滑、差值环比,还是基于阈值的桶过滤、多指标组合运算,都可以通过管道聚合原生实现,无需额外开发代码,极大简化了数据分析的开发成本。
简单总结:基础聚合负责「原始数据的分组和基础统计」,管道聚合负责「聚合结果的二次分析和高阶衍生计算」,二者搭配才能完成完整的业务数据分析。
常见的数值类型的管道聚合:
同级管道聚合与上层桶聚合平级,作用于所有桶的整体数据,用于统计全部分组指标的全局数值,输出全局汇总结果。
2.1.1 avg_bucket 桶均值聚合
遍历所有聚合桶的指定指标,计算全部桶数值的平均值。常用于统计日均销量、平均单量、平均访问量等全局均值指标。
2.1.2 sum_bucket 桶总和聚合
累加所有聚合桶的指定指标数值,得到全局总和。区别于基础sum聚合,它是对分组后的统计结果再次求和,可用于核对分段数据总汇总值。
2.1.3 max_bucket / min_bucket 桶极值聚合
遍历所有桶指标,筛选出数值最大/最小的桶及对应数值。可快速定位销量峰值、低谷、流量最高时段等极值场景。
2.1.4 stats_bucket / extended_stats_bucket 桶统计聚合
stats_bucket 一次性返回所有桶指标的 count、min、max、avg、sum 基础统计结果;extended_stats_bucket 在其基础上新增方差、标准差、变异系数等高级统计数据,适用于数据波动分析、异常数据研判场景。
2.2 父级数值管道聚合(单桶衍生计算)
父级管道聚合嵌套在桶聚合内部,针对每一个单独的桶做个性化数值衍生计算,为每个分组新增自定义指标,是时序数据分析的核心工具。
2.2.1 cumulative_sum 累计和聚合
最常用的数值管道聚合,按照桶的排序规则(默认时间正序),从第一个桶开始逐桶累加,生成当前桶的累计总值。核心用于统计年度累计销售额、累计用户数、累计交易量等时序累计指标,支持空桶补零、跳过空桶两种策略,保证数据连续性。
2.2.2 derivative 差值/环比聚合
计算相邻两个桶的指标差值,也就是一阶导数,可快速实现日环比、月环比、数据波动差值统计,精准捕捉数据增减变化幅度,适配业务数据异动监控场景。
2.2.3 moving_fn Moving Function 移动函数管道聚合
通过自定义滑动窗口大小,对连续多个桶的数值做平均计算,平滑时序数据的噪声、抹平短期数据波动,常用于流量、销量、监控指标的趋势分析,让数据走势更直观。
| 功能说明 | Groovy 脚本写法 |
|---|---|
| 滑动求和 | MovingFunctions.sum(values) |
| 滑动平均值 | MovingFunctions.mean(values) |
| 滑动最大值 | MovingFunctions.max(values) |
| 滑动最小值 | MovingFunctions.min(values) |
| 滑动中位数 | MovingFunctions.median(values) |
使用案例展示:
java
GET sales_data/_search
{
"size": 0,
"aggs": {
"terms_order_date": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day"
},
"aggs": {
"scale_stats":{
"stats": {
"field": "sales"
}
},
"pipeline_move":{
"moving_fn": {
"buckets_path": "scale_stats.sum",
"window": 2,
"script": "MovingFunctions.min(values)"
}
}
}
}
}
}
2.2.4 bucket_script 桶自定义公式聚合
支持通过Painless脚本,对同一个桶内的多个指标做自定义四则运算,是灵活性最高的数值聚合。可实现各类复杂业务指标计算,例如毛利率、转化率、客单价、增长率等衍生指标,解决固定聚合无法满足的个性化统计需求。
java
GET sales_data/_search
{
"size": 0,
"aggs": {
// 按天做时间分桶(桶聚合,必须有桶才能用管道聚合)
"terms_order_date": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day"
},
"aggs": {
// 先统计每个桶内 sales 的 min、max、avg、sum 等基础指标
"scale_stats": {
"stats": {
"field": "sales"
}
},
// bucket_script:父级管道聚合,桶内自定义公式计算
"pipeline_diff": {
"bucket_script": {
// 👉 buckets_path:专门【定义变量】
// 格式:"自定义变量名" : "上层聚合名称.子指标"
"buckets_path": {
// 定义变量 number,接收 scale_stats 聚合里的 min 值
"number": "scale_stats.min"
},
// 👉 script:用上面定义的变量写自定义计算公式
// 通过 params.自定义变量名 取值运算
"script": {
"source": "params.number * 10"
}
}
}
}
}
}
}
bucket_selector设置删选条件
java
GET sales_data/_search
{
"size": 0,
"aggs": {
"terms_order_date": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day"
},
"aggs": {
"scale_stats": {
"stats": {
"field": "sales",
"missing": 0
}
},
"pipeline_diff": {
"bucket_selector": {
"buckets_path": {
"number": "scale_stats.min"
},
"script": {
"source": """
params.number>10
"""
}
}
}
}
}
}
}
2.2.5 差值计算serial_diff
获取桶之间的差值serial_diff
java
GET sales_data/_search
{
"size": 0,
"aggs": {
"terms_order_date": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day"
},
"aggs": {
"scale_stats":{
"stats": {
"field": "sales"
}
},
"pipeline_diff":{
"serial_diff": {
"buckets_path": "scale_stats.sum",
"lag": 2 #指定是和第几个比较差值
}
}
}
}
}
}
2.2.6percentiles_bucket百分位获取
java
GET sales_data/_search
{
"size": 0,
"aggs": {
"terms_order_date": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day"
},
"aggs": {
"scale_stats":{
"stats": {
"field": "sales",
"missing": 0
}
},
"pipeline_diff":{
"moving_fn": {
"script": "MovingFunctions.sum(values)",
"buckets_path": "scale_stats.sum",
"window": 2,
"gap_policy": "insert_zeros"
}
}
}
},
"pipeline_percent":{
"percentiles_bucket": {
"buckets_path": "terms_order_date>scale_stats.max"
}
}
}
}
2.2.7 bucket_sort排序
必须写在子聚合中
java
GET sales_data/_search
{
"size": 0,
"aggs": {
"terms_order_date": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day"
},
"aggs": {
"scale_stats": {
"stats": {
"field": "sales",
"missing": 0
}
},
"sum_bucket_sort": {
"bucket_sort": {
"sort": [
{
"scale_stats.sum":{
"order":"desc"
}
}
]
}
}
}
}
}
}
总体使用案例展示:
数据形式:
java
{
"_index": "sales_data",
"_id": "aXPvM54B9Gv8TwgHTtwV",
"_score": 1,
"_source": {
"order_date": "2025-01-02",
"product_type": "电脑",
"sales": 1500,
"cost": 800
}
}
java
GET sales_data/_search
{
"size": 0,
"aggs": {
"group_by_date": {
"date_histogram": {
//创建直方图
"field": "order_date",
"calendar_interval": "day"
},
"aggs": {
//计算每天的钱
"daily_sales": {
"sum": {
"field": "sales"
}
},
"daily_cost": { "sum": { "field": "cost" } },
// 父级管道(每天内部计算)
"cumulative_sales": {
"cumulative_sum": { "buckets_path": "daily_sales" }
},
"sales_chain": {
"derivative": { "buckets_path": "daily_sales" }
}
}
},
// 同级管道(全局汇总计算)
"total_days_avg": {
"avg_bucket": { "buckets_path": "group_by_date>daily_sales" }
},
"total_sales_all": {
"sum_bucket": { "buckets_path": "group_by_date>daily_sales" }
},
"max_day_sales": {
"max_bucket": { "buckets_path": "group_by_date>daily_sales" }
},
"min_day_sales": {
"min_bucket": { "buckets_path": "group_by_date>daily_sales" }
},
"all_stats": {
"stats_bucket": { "buckets_path": "group_by_date>daily_sales" }
}
}
}