Elasticsearch中的三种分页策略深度解析:原理、使用及对比
俞事 发布于 阅读:619
1. From/Size分页
原理:
- 通过
from
(起始偏移量)和size
(每页数量)参数实现分页。 - 查询时,协调节点向所有分片请求数据,每个分片返回
from + size
条结果,协调节点汇总后截取from
后的size
条作为最终结果。 - 深度分页(如
from=10000
)时,分片需生成大量临时数据,内存和网络开销显著增加。
使用:
GET /index/_search
{
"from": 0,
"size": 10,
"query": { "match_all": {} }
}
限制:
- 默认最大
from + size
为10000
(可通过index.max_result_window
调整,但可能引发性能问题)。 - 不适用于大数据量深度分页。
2. Scroll分页
原理:
- 基于游标的遍历方式,适用于离线批量导出。
- 首次查询创建快照(数据视图固定),返回
_scroll_id
,后续通过此ID分批次拉取。 - 上下文在指定时间(如
1m
)内存活,占用堆内存资源。
使用:
# 初始化Scroll
GET /index/_search?scroll=1m
{
"size": 100,
"query": { "match_all": {} }
}
# 后续请求
GET _search/scroll
{
"scroll": "1m",
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAA..."
}
限制:
- 实时性差:快照创建后新增/更新的数据不可见。
- 资源消耗大:长期未关闭的Scroll会导致内存泄漏。
3. Search After分页
原理:
- 基于排序值(Sort)的分页,适用于实时深度分页。
- 每次查询使用上一页最后一条文档的排序值作为
search_after
参数,定位下一页起始位置。 - 避免全局排序,仅对当前页数据排序,性能更优。
使用:
# 首次查询
GET /index/_search
{
"size": 10,
"query": { "match_all": {} },
"sort": [
{"timestamp": "desc"},
{"_id": "asc"} // 确保排序唯一性
]
}
# 后续查询(使用上一页最后一条的排序值)
GET /index/_search
{
"size": 10,
"query": { "match_all": {} },
"sort": [
{"timestamp": "desc"},
{"_id": "asc"}
],
"search_after": [1640995200000, "abc123"]
}
限制:
- 必须指定唯一或足够唯一的排序字段组合(如时间戳+_id)。
- 不支持跳页,仅支持顺序翻页。
对比总结 | 维度 | From/Size | Scroll | Search After |
---|---|---|---|---|
性能 | 低效(深度分页时) | 高效(大数据量批处理) | 高效(实时深度分页) | |
实时性 | 实时 | 非实时(快照) | 实时 | |
内存占用 | 高(协调节点聚合) | 高(上下文保留) | 低(无上下文) | |
适用场景 | 小数据量简单分页 | 全量数据导出 | 大数据量深度分页 | |
跳页支持 | 支持 | 不支持 | 不支持 |