浅分页可使用 from/size,深分页应使用 search_after;需要跨页一致视图时再配合 PIT(Point in Time,时间点视图)。把 index.max_result_window 调大只会放大 CPU 与内存问题。
Table of contents
Open Table of contents
为什么第 1000 页昂贵
请求 from=9990,size=10 时,每个相关分片都要收集并排序前 10000 个候选,再由协调节点归并。客户端只拿 10 条,集群却做了与前 999 页相关的工作。默认结果窗口 10000 是保护边界。
search_after 不传页码,而是传上一页最后一条记录的排序值:
{
"size": 20,
"query": { "match": { "title": "java" } },
"sort": [{ "publishedAt": "desc" }, { "id": "asc" }],
"search_after": ["2026-09-04T01:00:00Z", "p-42"]
}
排序必须稳定且包含唯一的决胜字段(tie-breaker),否则相同时间的文档可能重复或漏掉。下一页必须保持相同查询和排序。
PIT 解决刷新变化
翻页期间索引刷新会改变候选集合。PIT 固定一个轻量视图,后续请求携带 PIT ID 与 keep_alive。使用完应关闭 PIT;大量长时间 PIT 会保留旧段并增加文件和磁盘压力。
Elastic 的分页文档推荐深分页采用 search_after,并在需要一致视图时配合 PIT。Scroll 更适合历史批处理,已不是在线深分页首选。
运行游标实验
mvn -Dtest=SearchArchitectureTest#searchAfterUsesScoreAndUniqueIdAsCursor test
实验把 (score, id) 作为游标,并验证第二页不会重复第一条。生产 API 应把游标编码并签名,包含查询哈希、排序值、索引版本和过期时间;客户端不能篡改排序值复用到另一查询。
下一步
继续阅读09-09 自定义分词、同义词和中文搜索,解决中文边界与业务词汇问题。