📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

Point In Time (PIT) 是 Easysearch 中的一种搜索机制,允许在特定时间点上的数据集上进行搜索,而不是在实时数据集上搜索。PIT 是实现深度分页(deep pagination)的推荐方式。

API #

POST /{index}/_pit

API 的作用 #

创建 PIT 上下文,用于在冻结的数据集上进行搜索。PIT 的主要功能包括:

  • 数据快照:锁定索引在特定时间点的段(segments)状态
  • 深度分页:避免传统分页在深页时的性能问题和结果不准确
  • 一致性搜索:在同一数据快照上执行多次不同查询
  • 搜索结果稳定:避免搜索过程中数据变化导致的结果不一致

创建 PIT 后,可以在搜索时使用 PIT ID 而不需要指定索引名称。

API 的参数 #

路由参数 #

参数类型是否必需描述
indexstring必需目标索引名称
支持:
- 单个索引:my-index
- 多个索引(逗号分隔):index1,index2
- 通配符:logs-*
- 数据流:my-data-stream

查询字符串参数 #

参数类型是否必需默认值描述
keep_alivetime必需PIT 的存活时间
每次使用 PIT 搜索时会延长该时间
建议值:1m, 5m, 1h
allow_partial_pit_creationboolean可选true是否允许部分失败时创建 PIT
true:部分索引失败时仍创建 PIT
false:任何索引失败时整个操作失败
preferencestring可选随机指定执行搜索的节点或分片
_local:优先使用本地节点
_primary:只查询主分片
routingstring可选文档的 _id将搜索请求路由到特定分片
expand_wildcardsstring可选open通配符可匹配的索引类型
open:开放状态的索引
closed:已关闭的索引
hidden:隐藏的索引
none:不展开通配符
all:所有状态的索引
可使用逗号分隔多个值

请求示例 #

基本请求 #

# 创建 PIT,存活 1 小时
POST /my-index/_pit?keep_alive=1h

带完整参数的请求 #

# 创建 PIT,存活 10 分钟,不允许部分失败
POST /logs-*/_pit?keep_alive=10m&allow_partial_pit_creation=false

多个索引 #

# 为多个索引创建 PIT
POST /index1,index2,index3/_pit?keep_alive=30m

数据流 #

# 为数据流创建 PIT
POST /my-data-stream/_pit?keep_alive=1h

响应示例 #

成功响应 #

{
  "pit_id": "o463QQEPbXktaW5kZXgtMDAwMDAxFnNOWU43ckt3U3IyaFVpbGE1UWEtMncAFjFyeXBsRGJmVFM2RTB6eVg1aVVqQncAAAAAAAAAAAIWcDVrM3ZIX0pRNS1XejE5YXRPRFhzUQEWc05ZTjdyS3dTcjJoVWlsYTVRYS0ydwAA",
  "_shards": {
    "total": 3,
    "successful": 3,
    "skipped": 0,
    "failed": 0
  },
  "creation_time": 1707033600000
}

响应字段说明 #

字段类型描述
pit_idstringBase64 编码的 PIT ID,用于后续搜索操作
_shards.totalinteger涉及的分片总数
_shards.successfulinteger成功创建 PIT 的分片数量
_shards.failedinteger创建 PIT 失败的分片数量
creation_timelongPIT 创建的时间戳(毫秒)

使用 PIT 进行搜索 #

创建 PIT 后,可以在搜索中使用 PIT ID:

GET /_search
{
  "pit": {
    "id": "o463QQEPbXktaW5kZXgtMDAwMDAxFnNOWU43ckt3U3IyaFVpbGE1UWEtMncAFjFyeXBsRGJmVFM2RTB6eVg1aVVqQncAAAAAAAAAAAIWcDVrM3ZIX0pRNS1XejE5YXRPRFhzUQEWc05ZTjdyS3dTcjJoVWlsYTVRYS0ydwAA",
    "keep_alive": "1m"
  },
  "query": {
    "match_all": {}
  },
  "size": 1000,
  "sort": [
    {"_shard_doc": "asc"}
  ]
}

深度分页示例 #

使用 PIT 和 search_after 实现深度分页:

GET /_search
{
  "pit": {
    "id": "pit_id_here",
    "keep_alive": "5m"
  },
  "query": {
    "match": { "message": "error" }
  },
  "size": 100,
  "sort": [
    {"@timestamp": "asc"},
    {"_shard_doc": "asc"}
  ],
  "search_after": [1707033600000, "shard_doc_value"]
}

PIT 生命周期管理 #

自动过期 #

  • PIT 在 keep_alive 时间后自动过期
  • 每次使用 PIT 搜索时会延长 keep_alive 时间

手动删除 #

使用 删除 point-in-time API 手动删除 PIT:

DELETE /_pit
{
  "pit_id": ["pit_id_1", "pit_id_2"]
}

PIT vs 传统分页 #

特性传统分页 (from/size)PIT + search_after
深度分页支持差(深页性能差)优秀
结果一致性数据变化时可能重复或遗漏一致的数据快照
性能深页时需要排序和丢弃大量结果恒定性能
内存使用需要维护深度优先游标维护轻量级 PIT 上下文

使用场景 #

  1. 深度分页:需要浏览超过 10000 条结果
  2. 一致性导出:需要导出完整的数据集
  3. 批量处理:分批处理大量数据
  4. 数据分析:对同一时间点的数据进行多次分析

注意事项 #

  1. keep_alive 是必需参数:创建 PIT 时必须指定存活时间
  2. 定期刷新:长时间使用 PIT 时,需定期搜索以延长存活时间
  3. 内存管理:未使用的 PIT 会占用内存,建议及时删除
  4. ID 保密:PIT ID 包含索引信息,不应泄露给未授权用户
  5. 不支持查询字符串参数:所有参数必须通过查询字符串传递,不能使用请求体

相关文档 #