3. 聚合查询基础:Elasticsearch 聚合框架概述、度量聚合、桶聚合、管道聚合
在领域建模驱动的搜索索引设计中,聚合查询是连接领域分析维度与索引存储结构的核心桥梁。Elasticsearch 聚合框架允许我们在搜索命中的文档集上实时计算统计指标、构建分类桶、并对聚合结果进行二次加工。本章将系统阐述聚合框架的三大支柱:度量聚合、桶聚合与管道聚合,并给出领域建模视角下的参数配置建议。
3.1 聚合框架整体架构
Elasticsearch 聚合(Aggregation)基于 doc_values 或 fielddata 在内存中构建列式数据结构,避免对原始文档的逐一遍历。聚合请求与搜索请求共享同一个 query 上下文,所有聚合计算仅在匹配文档集上执行。
领域建模提示:聚合查询的边界参数(如
size、shard_size、execution_hint)直接影响领域聚合结果的精度与性能。在配置索引映射时,应优先为聚合字段启用 doc_values: true(默认开启),避免运行时字段转换开销。
3.2 度量聚合(Metrics Aggregation)
度量聚合对匹配文档集的某个数值字段计算统计值,返回单一标量结果。根据计算方式分为单值度量与多值度量两类。
| 分类 | 聚合类型 | 返回值 | 典型领域场景 |
|---|---|---|---|
| 单值度量 | avg |
平均值 | 订单平均金额、响应平均延迟 |
sum |
总和 | 当日销售额、总库存量 | |
max / min |
最大值 / 最小值 | 最高温度、最早创建时间 | |
value_count |
非空文档计数 | 有效评价数、非空标签数 | |
| 多值度量 | stats |
count / min / max / avg / sum | 商品价格分布概览 |
extended_stats |
增加方差、标准差、总和平方 | 性能指标波动分析 |
边界参数配置:度量聚合通常不需要额外参数,但若字段为
keyword 类型且未启用 doc_values,聚合将回退到 fielddata,可能引发 OOM。领域建模阶段应确保所有聚合字段的映射包含 "doc_values": true。
// 度量聚合示例:计算订单金额的统计信息
GET /orders/_search
{
"size": 0,
"aggs": {
"amount_stats": {
"stats": {
"field": "total_amount"
}
}
}
}
// 响应示例
{
"aggregations": {
"amount_stats": {
"count": 12500,
"min": 9.9,
"max": 8999.0,
"avg": 342.15,
"sum": 4276875.0
}
}
}
3.3 桶聚合(Bucket Aggregation)
桶聚合将文档集划分为多个互斥的桶(Bucket),每个桶代表一个分组条件。桶聚合是领域驱动维度下钻的核心工具,支持嵌套组合形成多级分析树。
3.3.1 常用桶聚合类型
| 桶类型 | 分组依据 | 领域建模用途 | 关键参数 |
|---|---|---|---|
terms |
字段值精确匹配 | 按品类、地区、状态分组 | size、shard_size、min_doc_count |
date_histogram |
时间区间(年/月/日/时) | 按天统计销售额、按小时聚合日志 | interval、format、time_zone |
range / date_range |
自定义数值/时间区间 | 价格区间分布、订单生命周期阶段 | ranges[]、keyed |
filter / filters |
查询条件匹配 | 高价值用户 vs 普通用户对比 | filters 对象或数组 |
histogram |
等距数值区间 | 年龄分布、评分分布 | interval、offset |
3.3.2 桶聚合的边界参数陷阱
常见误区:
terms 聚合的 size 参数仅控制返回桶数,不控制参与计算的桶数。若 shard_size 过小,可能导致热门桶被截断,返回不精确的 Top N 结果。领域建模中,若需要精确统计所有桶(如枚举值分组),应设置 size: Integer.MAX_VALUE 并配合 min_doc_count: 1。
// 桶聚合嵌套示例:按品类分组,再按日期直方图下钻
GET /orders/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": {
"field": "category_id",
"size": 10,
"shard_size": 50
},
"aggs": {
"daily_sales": {
"date_histogram": {
"field": "order_date",
"interval": "day",
"format": "yyyy-MM-dd"
},
"aggs": {
"revenue": {
"sum": {
"field": "total_amount"
}
}
}
}
}
}
}
}
3.4 管道聚合(Pipeline Aggregation)
管道聚合不直接对文档集计算,而是以其他聚合的输出作为输入,执行二次加工。管道聚合分为父级管道(Parent)和兄弟管道(Sibling)两类。
3.4.1 管道聚合分类
| 类别 | 聚合类型 | 输入来源 | 典型用途 |
|---|---|---|---|
| 父级管道 | derivative |
同级度量聚合的历史值 | 计算时间序列的环比变化量 |
moving_fn |
同级度量聚合的滑动窗口 | 移动平均、平滑曲线 | |
cumulative_sum |
同级度量聚合的有序值 | 累计销售额、累计用户数 | |
| 兄弟管道 | avg_bucket |
兄弟桶聚合的度量输出 | 各品类平均销售额 |
max_bucket / min_bucket |
兄弟桶聚合的度量输出 | 找出销售额最高/最低的品类 | |
stats_bucket |
兄弟桶聚合的度量输出 | 跨桶的统计概览 |
3.4.2 管道聚合的领域建模约束
- 顺序依赖:管道聚合必须在被引用的聚合之后定义,且引用路径使用
buckets_path参数指定。 - 数据排序:父级管道(如
derivative)要求输入桶按时间或数值升序排列,否则结果无意义。 - 空桶处理:管道聚合遇到空桶时默认返回
null,可通过gap_policy参数配置为skip(跳过)或insert_zeros(补零)。
// 管道聚合示例:计算每日销售额的环比变化
GET /orders/_search
{
"size": 0,
"aggs": {
"sales_over_time": {
"date_histogram": {
"field": "order_date",
"interval": "day",
"format": "yyyy-MM-dd",
"order": { "_key": "asc" }
},
"aggs": {
"daily_revenue": {
"sum": { "field": "total_amount" }
},
"revenue_derivative": {
"derivative": {
"buckets_path": "daily_revenue"
}
}
}
}
}
}
// 响应片段
"buckets": [
{ "key_as_string": "2025-03-01", "daily_revenue": { "value": 12000 } },
{ "key_as_string": "2025-03-02", "daily_revenue": { "value": 13500 },
"revenue_derivative": { "value": 1500 } },
{ "key_as_string": "2025-03-03", "daily_revenue": { "value": 12800 },
"revenue_derivative": { "value": -700 } }
]
3.5 聚合查询的边界参数配置清单
在领域建模阶段,以下参数直接影响聚合结果的准确性与性能,建议在索引模板或查询模板中显式配置。
| 参数 | 所属聚合 | 默认值 | 领域建模建议 |
|---|---|---|---|
size |
terms | 10 | 若需全量枚举,设为 Integer.MAX_VALUE;否则按业务 Top N 设置 |
shard_size |
terms | size × 1.5 + 10 | 高基数场景建议手动调大,避免分片截断误差 |
min_doc_count |
terms | 1 | 过滤低频桶时设为 > 1,减少结果集大小 |
execution_hint |
terms | global_ordinals | 低基数枚举字段用 map 提升速度 |
interval |
date_histogram | — | 固定间隔;领域建模中优先使用 calendar_interval 避免时区偏移 |
gap_policy |
管道聚合 | skip | 时序分析中建议 insert_zeros 保持连续性 |
format |
date_histogram / date_range | epoch_millis | 领域展示层应指定 yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss |
领域建模最佳实践:在索引映射中为聚合字段设置
"doc_values": true 和 "index": false(若无需全文搜索),可同时降低存储开销与聚合内存占用。对于 keyword 类型的高基数字段(如用户 ID),建议使用 cardinality 聚合估算去重数,而非 terms 全量枚举。
3.6 本章小结
- 度量聚合提供标量统计值,是领域指标计算的基础单元。
- 桶聚合实现维度分组与下钻,支持多层嵌套形成分析树。
- 管道聚合对聚合结果进行二次加工,适用于环比、累计、移动平均等时序分析。
- 边界参数(
size、shard_size、gap_policy等)必须在领域建模阶段根据业务精度要求显式配置,避免默认值导致的精度损失或性能退化。