目录
[1. 文档概述](#1. 文档概述)
[2. 基础概念](#2. 基础概念)
[3. 深度优先遍历(depth_first)](#3. 深度优先遍历(depth_first))
[3.1 核心原理](#3.1 核心原理)
[3.2 执行流程(三级嵌套示例:省份→城市→用户等级)](#3.2 执行流程(三级嵌套示例:省份→城市→用户等级))
[3.3 配置示例](#3.3 配置示例)
[3.4 核心特点](#3.4 核心特点)
[3.5 适用场景](#3.5 适用场景)
[4. 广度优先遍历(breadth_first)](#4. 广度优先遍历(breadth_first))
[4.1 核心原理](#4.1 核心原理)
[4.2 执行流程(三级嵌套示例:省份→城市→用户等级)](#4.2 执行流程(三级嵌套示例:省份→城市→用户等级))
[4.3 配置示例(高基数生产场景)](#4.3 配置示例(高基数生产场景))
[4.4 核心特点](#4.4 核心特点)
[4.5 适用场景](#4.5 适用场景)
[5. 两种遍历模式全方位对比](#5. 两种遍历模式全方位对比)
[6. 生产避坑规范](#6. 生产避坑规范)
[6.1 广度优先(BFS)核心禁忌](#6.1 广度优先(BFS)核心禁忌)
[6.2 深度优先(DFS)核心禁忌](#6.2 深度优先(DFS)核心禁忌)
[7. 生产统一选型规范](#7. 生产统一选型规范)
[7.1 优先使用 深度优先(DFS)](#7.1 优先使用 深度优先(DFS))
[7.2 强制使用 广度优先(BFS)](#7.2 强制使用 广度优先(BFS))
[8. 总结](#8. 总结)
1. 文档概述
在 Elasticsearch 多层嵌套 Terms 聚合分桶场景中,遍历收集模式(collect_mode)直接决定查询性能、内存占用、聚合执行效率。ES 提供两种核心遍历策略:深度优先(depth_first,DFS) 、广度优先(breadth_first,BFS)。
本文档系统性讲解两种遍历模式的底层原理、执行流程、优缺点、适用场景、使用限制及生产最佳实践,解决多级嵌套聚合高基数卡顿、OOM、查询超时等常见问题,为线上聚合查询选型提供标准依据。
适用范围:ES 多级嵌套 terms 分桶统计、分组 TopN 分析、高基数字段聚合查询。
核心参数:collect_mode
2. 基础概念
ES 在执行多层嵌套桶聚合 时,需要遍历文档并逐层构建父桶、子桶、孙子桶数据。collect_mode 用于控制聚合数据的遍历顺序、桶收集、缓存策略。
关键特性:两种遍历模式不会改变最终聚合结果,仅影响执行性能与内存开销。
ES 默认聚合遍历策略:深度优先 depth_first。
3. 深度优先遍历(depth_first)
3.1 核心原理
深度优先采用分支优先、一路到底的递归遍历逻辑:优先完整计算完一个父桶下的所有子层级、叶子层级聚合数据,完成当前整条分支的统计后,再回溯处理下一个同级父桶。
简单理解:先算完一条完整链路,再算下一条链路。
3.2 执行流程(三级嵌套示例:省份→城市→用户等级)
-
读取第一个省份桶(如北京);
-
递归计算该省份下所有城市子桶;
-
继续递归计算每个城市下所有用户等级叶子桶;
-
当前省份全部分支计算完成,释放临时缓存;
-
遍历下一个省份桶,重复上述流程。
3.3 配置示例
POST /goods/_search
{
"size": 0,
"aggs": {
"province_agg": {
"terms": {
"field": "province",
"collect_mode": "depth_first"
},
"aggs": {
"city_agg": {
"terms": {
"field": "city"
},
"aggs": {
"level_agg": {
"terms": {
"field": "user_level"
}
}
}
}
}
}
}
}
3.4 核心特点
-
内存占用低:同一时间仅加载单个分支数据,无需缓存全量顶层桶,内存压力极小;
-
执行逻辑轻量化:天然适配层级嵌套结构,无额外分层计算开销;
-
不支持中间层剪枝:必须遍历完整分支才能统计桶文档数,无法在中间层级过滤无效小桶;
-
高基数场景性能差:若顶层桶数量极多,会产生大量无效分支计算,引发查询超时。
3.5 适用场景
-
低基数多级嵌套聚合(地区、分类、状态、类型等枚举字段);
-
无需中间层过滤、无需取 TopN 数据的全量统计场景;
-
服务器内存资源紧张,优先控制内存开销的场景;
-
常规业务报表、维度分组统计。
4. 广度优先遍历(breadth_first)
4.1 核心原理
广度优先采用分层遍历、逐层剪枝的逻辑:先完整计算当前层级所有桶数据,通过 size 参数过滤无效小桶,仅保留热门大桶,再基于剩余有效桶进行下一层级聚合计算。
简单理解:先分层、再过滤、后计算,从顶层逐层收敛计算量。
4.2 执行流程(三级嵌套示例:省份→城市→用户等级)
-
第一层:计算全量省份桶,通过 size 保留 TopN 热门省份,过滤小众省份;
-
第二层:仅对保留的热门省份,计算下属城市桶,再次过滤无效城市;
-
第三层:仅对剩余有效城市,执行用户等级聚合统计。
核心优势:提前淘汰无效桶,大幅减少下层聚合计算量。
4.3 配置示例(高基数生产场景)
POST /order/_search
{
"size": 0,
"aggs": {
"shop_agg": {
"terms": {
"field": "shop_id",
"size": 20,
"collect_mode": "breadth_first"
},
"aggs": {
"order_agg": {
"terms": {
"field": "order_id",
"size": 10
},
"aggs": {
"pay_agg": {
"terms": {
"field": "pay_type"
}
}
}
}
}
}
}
}
4.4 核心特点
-
支持分层剪枝:每一层均可通过 size 限制桶数量,彻底减少无效计算;
-
高基数场景性能极强:多层高基数嵌套下,性能远超深度优先;
-
内存开销更高:需要缓存当前层级全量桶数据,顶层基数过大易引发内存峰值;
-
场景限制严格:仅支持 terms 桶聚合,不支持指标聚合、直方图聚合。
4.5 适用场景
-
高基数字段多级嵌套(店铺ID、用户ID、订单ID、设备ID等);
-
业务需要 TopN 维度统计(热门店铺、热门商品、高频订单);
-
存在大量低频次无效小桶,需要提前过滤收敛计算量;
-
深度优先查询超时、耗时过高的大数据量聚合场景。
5. 两种遍历模式全方位对比
| 对比维度 | 深度优先(depth_first) | 广度优先(breadth_first) |
|---|---|---|
| 遍历逻辑 | 分支递归,一路到底 | 分层遍历,逐层收敛 |
| 内存占用 | 低,单分支缓存 | 高,整层桶缓存 |
| 剪枝能力 | 不支持中间层剪枝 | 支持分层 size 剪枝(核心优势) |
| 高基数性能 | 差,易超时 | 优异,大幅降低计算量 |
| 默认策略 | 是 | 否 |
| 适用数据 | 低基数、全量统计 | 高基数、TopN 统计 |
| 支持聚合类型 | 全量聚合 | 仅 terms 桶聚合 |
6. 生产避坑规范
6.1 广度优先(BFS)核心禁忌
-
禁止无限制使用 :BFS 必须配合
size参数,超高基数顶层字段不限制 size 会直接引发堆内存溢出(OOM); -
不支持非 terms 聚合:指标聚合(sum、avg、count)、histogram、range 聚合不能使用 BFS;
-
单层聚合无需启用:仅多级嵌套聚合存在选型差异,单层 terms 聚合两种模式无区别。
6.2 深度优先(DFS)核心禁忌
- 高基数多级嵌套场景禁止直接使用默认 DFS,会产生海量无效分支计算,导致接口超时、集群负载飙升。
7. 生产统一选型规范
7.1 优先使用 深度优先(DFS)
满足任意一条即可使用默认 DFS:
-
聚合维度为低基数枚举字段(地区、分类、状态、渠道);
-
业务需要全量维度统计,无需过滤小桶;
-
集群内存资源紧张,需要控制聚合内存开销。
7.2 强制使用 广度优先(BFS)
满足任意一条必须启用 BFS + size 限制:
-
聚合字段为高基数业务字段(用户ID、订单ID、设备ID、店铺ID);
-
多级嵌套聚合 + 业务取 TopN 热门数据;
-
默认 DFS 查询耗时过长、频繁超时;
-
数据量大、无效小桶占比极高的统计场景。
8. 总结
-
深度优先 DFS:默认策略、低内存、适合低基数全量嵌套统计,无额外性能开销,是常规报表首选;
-
广度优先 BFS:分层剪枝、性能强悍、专为高基数多级 TopN 聚合设计,是大数据量优化核心方案;
-
核心选型公式:低基数全量用 DFS,高基数 TopN 用 BFS+size;
-
BFS 是 ES 多级高基数聚合性能优化的低成本、高收益最优实践。