Elasticsearch 分页查询的 from+size 有什么缺陷?如何优化深度分页?比较scroll API与search_after的差异
Elasticsearch 分页查询的 from+size 机制
Elasticsearch中的分页查询from+size机制是一种直观且常用的分页方式,其工作原理和使用方法如下:
工作原理
from+size分页方式的原理相对简单,执行一个搜索查询并指定了from和size参数时,Elasticsearch会进行以下步骤:
分发查询:Elasticsearch会将查询请求分发到所有相关的分片上。
查询分片:每个分片都会执行查询,并返回前from+size条符合条件的文档(但实际上只会用到最后的size条)。
合并和排序:协调节点(通常是执行搜索的Elasticsearch节点)会收集所有分片返回的结果,将它们合并成一个全局的结果集,并根据查询中指定的排序规则进行排序。
截断和返回:然后,协调节点会从排序后的结果集中截取从from位置开始的size条记录,并将它们返回给客户端。
使用方法
在Elasticsearch中,使用from和size进行分页查询的DSL(Domain Specific Language)示例如下:
GET /your_index/_search
{"query": {"match_all": {} // 这里可以替换为任何你需要的查询条件},"from": 0, // 从第几条记录开始,索引从0开始"size": 10, // 返回的记录条数"sort": [{"field_name": {"order": "asc"}}] // 可选,根据某个字段进行排序
}
在这个例子中,from参数指定了从哪一条记录开始返回,size参数指定了要返回的记录条数。假设有一个名为products的索引,想要搜索名称中包含“apple”的产品,并且从第10条记录开始返回10条结果,按价格升序排序,可以这样写:
GET /products/_search
{"query": {"match": {"name": "apple"}},"from": 9, // 注意,索引从0开始,所以第10条记录的索引是9"size": 10,"sort": [{"price": {"order": "asc"}}]
}
优缺点及适用场景
优点:直观易用,开发者可以很容易地指定要返回的记录范围和数量。
缺点:
性能问题:当from值很大时,Elasticsearch需要遍历大量数据才能找到起始位置,然后返回size条记录,这会导致查询性能下降,尤其是在数据量很大的情况下。
资源消耗:深度分页会消耗大量CPU和内存资源,对集群性能造成压力。
适用场景:适用于数据量不大、实时性要求高的场景。
Elasticsearch 分页查询的 from+size 机制在深度分页场景中存在以下核心缺陷及优化方案:
一、from+size 分页机制缺陷
-
内存消耗指数级增长
- 深度分页时(如 from=10000),每个分片都需要构建 (from+size) 条结果的优先级队列
- 协调节点需要合并所有分片结果,内存消耗公式:
(number_of_shards * (from + size))
-
默认最大限制
max_result_window
默认 10000 条2- 突破限制需调整设置,但会显著影响性能
-
实时性缺陷
- 跨页结果可能包含重复或缺失数据(数据变更时)
二、深度分页优化方案
1. Scroll API
GET /_search/scroll
{"scroll" : "5m","scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4W..."
}
特点:
- 创建搜索上下文快照
- 适用于大规模数据导出
- 保持上下文需定期续期(scroll 参数)
- 内存消耗随分页深度线性增长
2. Search After
GET /_search
{"size": 10,"sort": [{"timestamp": "desc"},{"_id": "asc"}],"search_after": [1625000000000, "abc123"]
}
特点:
- 基于上一页最后结果定位
- 必须使用唯一排序字段组合(建议包含 _id)
- 实时性强,适合用户界面分页
- 无上下文维护开销
三、核心差异对比
特性 | Scroll API | Search After |
---|---|---|
数据一致性 | 快照数据 | 实时数据 |
内存消耗 | 随分页线性增长 | 恒定 O(1) |
适用场景 | 批量导出/ETL | 实时分页/用户界面 |
上下文保持 | 需要显式维护 | 无状态 |
最大返回量 | 无限制 | 受 index.max_result_window 限制 |
四、实践建议
- 分页深度 < 1000 页:使用 from+size
- 深度分页+数据导出:使用 Scroll API
- 实时分页+用户界面:使用 Search After(需搭配唯一排序字段)
- 需强制排序时,优先使用 search_after + PIT(Point in Time)组合5