Point In Time (PIT) 是 Easysearch 中的一种搜索机制,允许在特定时间点上的数据集上进行搜索,而不是在实时数据集上搜索。PIT 是实现深度分页(deep pagination)的推荐方式。
API #
POST /{index}/_pit
API 的作用 #
创建 PIT 上下文,用于在冻结的数据集上进行搜索。PIT 的主要功能包括:
- 数据快照:锁定索引在特定时间点的段(segments)状态
- 深度分页:避免传统分页在深页时的性能问题和结果不准确
- 一致性搜索:在同一数据快照上执行多次不同查询
- 搜索结果稳定:避免搜索过程中数据变化导致的结果不一致
创建 PIT 后,可以在搜索时使用 PIT ID 而不需要指定索引名称。
API 的参数 #
路由参数 #
| 参数 | 类型 | 是否必需 | 描述 |
|---|---|---|---|
index | string | 必需 | 目标索引名称 支持: - 单个索引: my-index- 多个索引(逗号分隔): index1,index2- 通配符: logs-*- 数据流: my-data-stream |
查询字符串参数 #
| 参数 | 类型 | 是否必需 | 默认值 | 描述 |
|---|---|---|---|---|
keep_alive | time | 必需 | 无 | PIT 的存活时间 每次使用 PIT 搜索时会延长该时间 建议值: 1m, 5m, 1h 等 |
allow_partial_pit_creation | boolean | 可选 | true | 是否允许部分失败时创建 PITtrue:部分索引失败时仍创建 PITfalse:任何索引失败时整个操作失败 |
preference | string | 可选 | 随机 | 指定执行搜索的节点或分片_local:优先使用本地节点_primary:只查询主分片 |
routing | string | 可选 | 文档的 _id | 将搜索请求路由到特定分片 |
expand_wildcards | string | 可选 | 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_id | string | Base64 编码的 PIT ID,用于后续搜索操作 |
_shards.total | integer | 涉及的分片总数 |
_shards.successful | integer | 成功创建 PIT 的分片数量 |
_shards.failed | integer | 创建 PIT 失败的分片数量 |
creation_time | long | PIT 创建的时间戳(毫秒) |
使用 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 上下文 |
使用场景 #
- 深度分页:需要浏览超过 10000 条结果
- 一致性导出:需要导出完整的数据集
- 批量处理:分批处理大量数据
- 数据分析:对同一时间点的数据进行多次分析
注意事项 #
- keep_alive 是必需参数:创建 PIT 时必须指定存活时间
- 定期刷新:长时间使用 PIT 时,需定期搜索以延长存活时间
- 内存管理:未使用的 PIT 会占用内存,建议及时删除
- ID 保密:PIT ID 包含索引信息,不应泄露给未授权用户
- 不支持查询字符串参数:所有参数必须通过查询字符串传递,不能使用请求体





