6.3 管道聚合:在聚合结果上再计算


文档摘要

6.3 管道聚合:在聚合结果上再计算 本节摘要:管道聚合(pipeline aggregations)的消费对象不是文档,而是别的聚合结果——在每日桶上算环比(derivative)、累计(cumulativesum)、桶间均值(avgbucket)、自定义公式(bucketscript)。本节讲兄弟管道与父管道两族的分工与写法,最后用一张"日工单量环比看板"把全章三层能力串成一个请求。 在聚合之上再造聚合 两族管道:兄弟与父 桶结果出来后常有一句后续:"给我算算环比""把每天的平均值画条基准线"。这类运算的对象是桶,不是文档——普通聚合无能为力,管道聚合登场。它分两族:兄弟管道与原聚合平级,对一串桶的指标做整体运算(均值、最值);父管道嵌在原聚合内部,对每个桶产出新指标(环比、累计)。

6.3 管道聚合:在聚合结果上再计算

本节摘要:管道聚合(pipeline aggregations)的消费对象不是文档,而是别的聚合结果——在每日桶上算环比(derivative)、累计(cumulative_sum)、桶间均值(avg_bucket)、自定义公式(bucket_script)。本节讲兄弟管道与父管道两族的分工与写法,最后用一张"日工单量环比看板"把全章三层能力串成一个请求。

在聚合之上再造聚合

两族管道:兄弟与父

桶结果出来后常有一句后续:"给我算算环比""把每天的平均值画条基准线"。这类运算的对象是桶,不是文档——普通聚合无能为力,管道聚合登场。它分两族:兄弟管道与原聚合平级,对一串桶的指标做整体运算(均值、最值);父管道嵌在原聚合内部,对每个桶产出新指标(环比、累计)。分族记法:兄弟是"给整排桶算一个数",父是"给每个桶再添一列"。

先看兄弟族的基准线:

GET tickets/_search { "size": 0, "aggs": { "per_day": { "date_histogram": { "field": "created_at", "calendar_interval": "day", "time_zone": "+08:00" }, "aggs": { "daily_count": { "value_count": { "field": "ticket_id" } } } }, "avg_daily": { "avg_bucket": { "buckets_path": "per_day[_count]" } }, "peak_daily": { "max_bucket": { "buckets_path": "per_day[_count]" } } } }

avg_daily 与 per_day 平级,指名道姓地引用它的桶计数(buckets_path 里的 _count 是每桶文档数)。返回里除了每天一桶,还多出"日均 137、峰值 421"两个兄弟级数字——折线图上的一条基准线与一个峰值标记,一个请求打包。

再看父族的环比与累计:

GET tickets/_search { "size": 0, "aggs": { "per_day": { "date_histogram": { "field": "created_at", "calendar_interval": "day", "time_zone": "+08:00" }, "aggs": { "daily_count": { "value_count": { "field": "ticket_id" } }, "day_over_day": { "derivative": { "buckets_path": "daily_count" } }, "running_total": { "cumulative_sum": { "buckets_path": "daily_count" } } } } } }
per_day.buckets 形如(节选): 08-19 daily_count=154 day_over_day=null(首桶无前值) running_total=154 08-20 daily_count=189 day_over_day=35 running_total=343 08-21 daily_count=131 day_over_day=-58 running_total=474

derivative 给每桶算"与上一桶的差"即环比增量,首桶无前值为空;cumulative_sum 给每桶算"从开头到当前的累计"。两个父管道都嵌在 per_day 内部,与 daily_count 同级——它们消费的是兄弟 daily_count 的桶值,这就是 buckets_path 的指向规则:写"谁的哪个指标"。

自定义公式:bucket_script

四个内置运算不够表达业务口径时,bucket_script 上场——给每桶一个表达式:

GET tickets/_search { "size": 0, "aggs": { "per_day": { "date_histogram": { "field": "created_at", "calendar_interval": "day", "time_zone": "+08:00" }, "aggs": { "created": { "value_count": { "field": "ticket_id" } }, "resolved": { "filter": { "term": { "status": "resolved" } } }, "resolve_rate": { "bucket_script": { "buckets_path": { "c": "created", "r": "resolved._count" }, "script": "params.r / params.c * 100" } } } } } }

resolve_rate 每天算一个"当日解决率":resolved 是嵌套的过滤桶(命中即计数),bucket_script 引用两个路径做除法。表达式语言支持四则与条件,够用且不沉重;更复杂的口径应该在写入端预计算成字段(第 3 章的思路),而不是把业务逻辑塞满报表请求。

一张环比看板的诞生

背景:运营要一张"日工单量、环比、累计月量、解决率基准线"四合一看板,数据八月当月。操作:外层 date_histogram 按天加时区;内层挂 value_count(日量)、derivative(环比)、cumulative_sum(累计)、filter 加 bucket_script(解决率);平级再加 avg_bucket(日均基准线)。一个请求组装完成。结果:响应即看板数据源,前端直接渲染四条序列;对比旧方案(应用层取回原始桶再自己算),请求往返从四次降为一次,应用代码里的口径计算全部消失。解读:管道聚合把"口径"从应用代码搬进请求里,口径变更有据可查(请求即文档),也避免了应用层取全量桶再运算的带宽浪费。变式:解决率要按周平滑时,加 moving_fn 移动窗口;要预警"环比骤降三成"时,在 bucket_script 里输出布尔标记,由告警系统消费。

⚠️ 常见坑:buckets_path 写错层级是最常见的报错来源——父管道引用同级指标、兄弟管道引用整条桶路径,差一个点都找不到。写复杂管道时先画 6.2 那样的嵌套树,对着树写路径。

💡 关键直觉:报表分三层组装——桶搭骨架、指标填数值、管道补口径。当你在应用代码里写"取回桶再算一遍"时,多半有一条管道聚合能替你干这活。

三层收束

  • 管道聚合消费聚合结果:兄弟族对整排桶算一个数,父族给每桶添一列。
  • derivative 环比、cumulative_sum 累计、avg_bucket 基准线、bucket_script 自定义口径。
  • buckets_path 按"谁的哪个指标"书写,嵌套树画清楚再写路径。
  • 复杂口径优先写入端预计算,报表端管道保持轻薄。

统计视角收工。下一章回到文档本身:有些文档结伴而来(数组与嵌套)、有些带着坐标出生——复杂形态的旅程开始。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U