首页/数据/NoSQL 速查/PIT 搜索上下文(point in time)
Elasticsearch89 条

PIT 搜索上下文(point in time)

PIT 为一次搜索会话固定索引视图,与 search_after 搭配实现稳定且省资源的深分页;用完需显式关闭,否则会一直保留段引用。

NoSQL 速查数据更新于 2026-10-13

PIT 是干什么的

PIT(point in time)为一次搜索会话固定索引视图:创建后拿到一个 id,后续 search 请求在请求体里带上它,就相当于一直在同一份数据快照上检索。它解决了索引持续写入时普通 search_after 结果漂移的问题,也是官方推荐的深分页方式。代价是 PIT 持有期间相关段无法合并,用完必须显式关闭。

基本信息

创建POST /<index>/_pit?keep_alive=1m
使用search 请求体写 "pit": { "id": "...", "keep_alive": "1m" },可不指定索引
收尾DELETE /_pit,请求体传 id
分页搭配与 search_after 搭配使用,不能同时带 from
适用版本Elasticsearch 7.10 起提供 PIT API

完整流程

完整流程
# 1 创建 PIT,保留 1 分钟
POST /my-index/_pit?keep_alive=1m

# 2 用 PIT 检索:不能再用 from,排序里加 _shard_doc 兜底成唯一序
GET /_search
{
  "size": 10,
  "query": { "match": { "title": "elastic" } },
  "pit": { "id": "<pit_id>", "keep_alive": "1m" },
  "sort": [ { "@timestamp": "desc" }, { "_shard_doc": "asc" } ],
  "search_after": [ 1699999999000, 42 ]
}

# 3 收尾:关闭 PIT,释放段引用
DELETE /_pit
{ "id": "<pit_id>" }

典型使用场景

  • 深分页:翻到几千页之后,用 PIT + search_after 替代 from+size
  • 一致性遍历:导出期间索引仍在写入,需要固定视图
  • 报表批量取数:保证同一批次的数据口径一致
  • 游标式翻页:前端滚动加载,用 _shard_doc 保证全序
  • 跨索引会话:一次遍历同时覆盖多个索引并固定视图

参数与注意

参数作用注意
keep_alivePIT 与上下文保留时长每次带 pit 的请求可续期
idPIT 标识响应会返回新 id,翻页要用最新的
_shard_doc分片内文档序号与其他排序字段组合成唯一全序
from起始偏移使用 pit 时不允许出现
keep_alive 过期后再发请求会报上下文丢失(context missing),长任务要把保留时长设得比单页耗时宽裕,并在每页请求里自动续期。
PIT 持有的段无法参与合并,时间窗越宽、开启时间越长,对段合并与磁盘回收的推迟越明显;遍历结束或异常退出后都要确认没有残留 PIT。

为什么深分页需要它

from 加 size 的深分页要求协调节点在每个分片上各取前若干条再归并,翻得越深开销越大;search_after 用上一页最后一条的排序值当游标,把开销压到接近常数。但只有游标还不够:索引在翻页期间持续写入,排序值会变化,可能出现重复或漏掉的文档。PIT 把索引视图固定下来,两者配合才能既省资源又保证遍历结果自洽。

PIT 的价值在写入活跃的场景:纯只读索引上 search_after 配固定排序已经足够稳定,不必额外承担 PIT 保留段带来的合并推迟成本。

易错点

  • 忘记关闭 PIT 会一直占用段引用,段合并受阻、磁盘迟迟不回收
  • keep_alive 设得过短,长任务中途报上下文丢失需要从头再来,务必按单页最大耗时留余量
  • 使用 PIT 的查询不能带 from,from 与 search_after 混用会直接报错
  • 跨索引 PIT 要求索引结构兼容,字段类型或分片配置差异大的索引放在同一个 PIT 里容易出问题

数据来源与参考

  • Elasticsearch Guide: Point in time API
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌