6.2 桶聚合:把文档分进格子


文档摘要

6.2 桶聚合:把文档分进格子 本节摘要:桶聚合(bucket aggregations)给每个文档发一张格子门票:terms 按词条分格、range 按区间分格、datehistogram 按时间切片分格;格子里还能再嵌套子聚合,一层套一层长成完整报表。本节讲三种主力桶的写法、嵌套语法、以及 terms 桶"分片各自取前 N 再归并"的取数边界——它决定报表数字什么时候会有小误差、怎么核对。 把文档分进格子 terms:按词条分格 最常用的桶是 terms:统计每种状态各有多少工单: 桶结果按文档数降序,size 限定返回桶数;被裁掉的文档记在 sumotherdoccount 里——它不是错误,是"其余"那一格。terms 桶吃 keyword 词条或数值,text 老规矩走子字段。

6.2 桶聚合:把文档分进格子

本节摘要:桶聚合(bucket aggregations)给每个文档发一张格子门票:terms 按词条分格、range 按区间分格、date_histogram 按时间切片分格;格子里还能再嵌套子聚合,一层套一层长成完整报表。本节讲三种主力桶的写法、嵌套语法、以及 terms 桶"分片各自取前 N 再归并"的取数边界——它决定报表数字什么时候会有小误差、怎么核对。

把文档分进格子

terms:按词条分格

最常用的桶是 terms:统计每种状态各有多少工单:

GET tickets/_search { "size": 0, "aggs": { "by_status": { "terms": { "field": "status", "size": 10 } } } }
{ "aggregations": { "by_status": { "buckets": [ { "key": "pending", "doc_count": 1620 }, { "key": "resolved", "doc_count": 1288 }, { "key": "escalated", "doc_count": 356 } ], "sum_other_doc_count": 949 } } }

桶结果按文档数降序,size 限定返回桶数;被裁掉的文档记在 sum_other_doc_count 里——它不是错误,是"其余"那一格。terms 桶吃 keyword 词条或数值,text 老规矩走子字段。

range 与 date_histogram:按区间和按时间分格

数值分格用 range,时间报表用 date_histogram:

GET tickets/_search { "size": 0, "aggs": { "reply_buckets": { "range": { "field": "first_reply_minutes", "ranges": [ { "to": 15 }, { "from": 15, "to": 60 }, { "from": 60 } ] } } } }
GET tickets/_search { "size": 0, "aggs": { "per_day": { "date_histogram": { "field": "created_at", "calendar_interval": "day", "time_zone": "+08:00", "min_doc_count": 0 } } } }

date_histogram 有两个参数直接决定报表口径:time_zone 不设就按协调世界时切天,中国用户会把凌晨八小时算进前一天——按本地日切报表必设时区;min_doc_count 设零让空日子也出格,折线图不断轴。calendar_interval 按日历切(月有大小),fixed_interval 按固定时长切(严格等宽),报表口径要写清用的哪个。

嵌套:格子里再算数

桶的威力在嵌套——每格之内再挂子聚合:

GET tickets/_search { "size": 0, "aggs": { "per_day": { "date_histogram": { "field": "created_at", "calendar_interval": "day", "time_zone": "+08:00" }, "aggs": { "by_status": { "terms": { "field": "status" }, "aggs": { "avg_reply": { "avg": { "field": "first_reply_minutes" } } } } } } } }

请求的缩进结构就是结果树的形状:每天一桶,桶内按状态再分桶,最内层算平均响应分钟——一张"每日各状态工单量与平均响应"的二维表就此成型。嵌套可以有合理深度(两三层常见),但每层都是笛卡尔式扩张,层级越深、桶数越多、内存与耗时越大,报表设计时先算桶数量级。

嵌套树与取数边界

嵌套树与取数边界

一次报表口径的完整推导

背景:运营要"按客服分组、按天看处理量"的热力图,客服约二百人。操作:外层 date_histogram 按天、内层 terms 按 assignee,size 先设二十;上线第一周收到反馈"某些天的客服排名每天略有跳动"。排查:看响应里 doc_count_error_upper_bound 为 3,而第二十名附近几个客服日计数在 4 上下——误差上界与计数同量级,排序自然抖动。修复:客服总数二百,把 terms 的 size 提到二百五(大于基数),排序稳定;请求耗时可接受(每天二百桶乘以三十天,共六千桶)。解读:terms 的 size 不是"显示多少"而是"分片保留多少",基数已知且可控时,size 盖过基数即可消除抖动。变式:基数不可控(比如按城市)时,接受近似并在界面标注"前二十为精确排序",或改用按城市预聚合的汇总索引(第 9 章的思路)。

⚠️ 常见坑:date_histogram 忘设 time_zone,跨时区团队各看各的"天",数字对不上开三小时会。按本地日切报表,时区参数是口径的一部分,写进报表注释。

💡 关键直觉:桶是格子,嵌套是格子里的格子,而 size 是分片端的筛子。读任何 terms 报表前先看两件事:sum_other_doc_count 裁掉了多少、误差上界多大——数字的信用额度写在响应里。

考核与自测

考核点 达标标准
三桶选型 terms、range、date_histogram 各配一个真实业务需求
时区口径 说出本地日报表必须带的参数与缺省行为
误差判读 用误差上界与头部桶差距判断排序可信度
size 语义 区分"显示条数"与"分片保留数"两种 size

易错点补充

  • 空桶参数忘配:折线图断轴先怀疑没设空桶参数,空日子也要出格。
  • 嵌套层级贪深:三层以上桶数笛卡尔式膨胀,先算桶数量级再写请求。

格子里的收成

  • 三种主力桶:terms 按词条、range 按区间、date_histogram 按时间;时区与空桶参数决定报表口径。
  • 嵌套结构即结果树,层级深度与桶数要预估,两级嵌套是报表常态。
  • terms 是分片各自取前 N 再归并,误差上界随响应返回;size 盖过基数即稳。
  • sum_other_doc_count 是"其余"格,别当成错误,也别视而不见。

格子有了、数算完了,下一节让格子之间互相运算:管道聚合把环比、排名、累计一次性补齐。


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