跳到正文
Elaine Blog
返回

深分页、游标与 Search After

Elasticsearch 与搜索架构

浅分页可使用 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 自定义分词、同义词和中文搜索,解决中文边界与业务词汇问题。


分享这篇文章:

上一篇
Spring Boot 搜索服务实战
下一篇
自定义分词、同义词和中文搜索