from+size分页:
from:起使数据的位置(不是页数,是位置)
size:单页返回的数据量大小
GET page_study_index/_search
{
"track_total_hits": true, #这个属性慎用
"from": 0,
"size":1
}
from size的窗口限制是10000,size+from<=10000,下面是错误信息:
type": "illegal_argument_exception",
"reason": "Result window is too large, from + size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."
通过上面的错误信息我们可以发现通过修改setting中的设置可以将这个窗口变大:
PUT page_study_index/_settings
{
"max_result_window":20000
}
PUT page_study_index/_settings
{
"index": {
"max_result_window": 20000
}
}
之后就可以查询20000内置的数据了。但是这个数值要谨慎开启,因为数值的过大影响es的效率。
size数值的最佳设置:
每一个source数据的大小在1KB以内,每次查询的数据在2MB以内
Search after 参照点 深度分页:
GET index_test/_search
{
"size": 20, // 每次取20条
"query": { "match_all": {} },
"sort": [ { "timestamp": "desc" } ], // 按时间倒序
"search_after": [ 1780268648000 ] // 核心:从这个时间戳之后开始查
}
根据上一页最后一条数据的排序值,来定位下一页开始的位置。 它是深分页最优方案,专门解决:
- from + size 深分页(如 page=1000,size=20)性能极差
- max_result_window 限制(默认只能查前 10000 条)
- 上亿数据分页
必须遵守的 3 条规则
- 必须带 sort 排序(search_after 依赖排序值定位)
- search_after 的值 = 上一页最后一条数据的排序字段值
- 不支持跳页(不能直接点第 100 页,只能一页一页往后翻)
Point in time查询
PIT(Point in Time) ,中文译为时间点视图 ,是 Elasticsearch 7.10+ 版本推出的轻量级数据快照机制。
简单理解:PIT 会锁定索引在某一时刻的静态数据视图 ,后续所有基于该 PIT 的查询、分页操作,都会基于这一固定快照执行,完全不受索引实时新增、修改、删除数据的影响。
PIT 仅保存数据视图的元数据,不复制原始数据,占用资源极低,是 ES 官方推荐的上亿数据深分页、全量数据导出、滚动查询的企业级方案。
PIT解决的核心问题:
在未使用 PIT 时,常规 search_after 分页存在严重的数据一致性问题,场景如下:
-
数据偏移、重复、漏数据 :分页查询过程中,若索引有新数据写入、旧数据更新/删除,ES 数据物理排序会发生变化,导致下一页
search_after定位错乱,出现重复查询或数据丢失。 -
无法保证分页一致性 :普通
search_after每次查询都会读取最新索引视图,多次分页查询的数据源视图不统一。 -
规避深分页性能限制 :突破
max_result_window10000 条的默认分页上限,支持海量数据无上限滚动分页。
PIT 核心价值 :固定查询视图,让多次分页查询基于同一时间点的静态数据,彻底解决分页数据错乱问题,同时保障海量数据分页性能。
PIT 核心特性
-
轻量无数据拷贝:仅记录索引分片、版本、时间点元数据,不复制文档数据,内存开销极小。
-
视图隔离:PIT 创建后,索引后续的增删改操作,不会影响当前 PIT 的查询结果。
-
必须配合 search_after :PIT 不支持页码分页,仅用于滚动深分页,需与
search_after组合使用。 -
生命周期可控 :通过
keep_alive设置存活时间,超时自动销毁,也可手动提前删除。 -
查询参数限制:使用 PIT 查询时,不可指定 index、routing、preference 参数,所有数据源信息均继承自 PIT 快照。
完整实操流程
PIT 分页固定四步流程:创建 PIT 视图 → 首次分页查询 → 滚动分页查询 → 销毁 PIT
1. 创建 PIT 时间点视图
锁定目标索引当前数据状态,生成唯一的 PIT ID,指定视图存活时间。
POST page_study_index/_pit?keep_alive=5m
返回结果示例:
{ "id": "46ToAwMDcGFnZV9zdHVkeV9pbmRleAAEWjFhY...(唯一PIT-ID)" }
参数说明:keep_alive 表示 PIT 视图的存活时长,分页耗时久可设置 10m、30m,避免视图过期失效。
2. 第一页查询(无 search_after)
首次查询无需 search_after,携带 PIT-ID、固定排序规则,获取首页数据,并记录最后一条数据的排序值。
GET _search
{
"pit": {
"id": "上面返回的PIT-ID",
"keep_alive": "5m" // 续期视图时长
},
"size": 20,
"sort": [
{ "timestamp": "desc" }
]
}
💡 最佳实践:海量数据分页可使用"sort": ["_shard_doc"],这是 ES 内置唯一排序字段,性能最优、无重复值,避免排序冲突。
3. 滚动分页查询(第二页及以后)
提取上一页最后一条数据的 sort 排序值 ,填入search_after,基于固定 PIT 视图向后滚动查询。
GET _search
{
"pit": {
"id": "-6zrAwEQcGFnZV9zdHVkeV9pbmRleBZlNy0ycllYVFFpUy00XzRsOFR3VUV3ABZuZlYzVjBoQlJRU1J6dUh5THJrMEZRAAAAAAAAAZHoFnBKNGpYOWgyU3JtMmRNNkdXRnFhQVEAARZlNy0ycllYVFFpUy00XzRsOFR3VUV3AAA=",
"keep_alive": "5m"
},
"sort": [
{
"number": {
"order": "desc"
}
}
],
"size":2,
"search_after": [
"99998"
]
}
循环执行此步骤,直到查询结果为空,代表数据分页完毕。
4. 手动销毁 PIT(必做)
PIT 超时前会一直占用集群资源,分页结束后必须手动删除,释放资源。
# 删除指定 PIT DELETE _pit { "id": "你的PIT-ID" }
Scroll 滚动查询
一、Scroll 查询核心概念
Scroll 是 Elasticsearch旧版经典深分页/全量遍历方案,是 ES7.10 之前主流的海量数据分页方式,现已被官方逐步废弃。
普通 search 查询是「实时快照、单次查询」,而 Scroll 查询的核心逻辑是:第一次查询时生成一个持久化索引快照上下文 ,后续每一次滚动查询,都基于这一份固定快照持续向后取数,不再读取最新索引数据。
核心定位:用于批量、全量、大批量数据导出、数据同步场景,不用于前端普通分页。
二、Scroll 核心原理
-
首次 scroll 查询 :ES 遍历匹配数据,生成一个快照上下文 ,记录当前索引所有分片的数据状态、文档排序、遍历指针,同时返回唯一
scroll_id。 -
后续滚动查询 :客户端携带
scroll_id持续请求,ES 基于快照上下文,从上次遍历位置继续向后取数,不会重新检索索引、不会感知新数据变更。 -
快照生命周期 :通过
scroll=时间控制快照存活时间,超时自动销毁上下文,释放资源。
简单理解:第一次查询拍照定格数据,后续所有翻页都是翻看这张照片。
三、Scroll 完整实操流程(标准旧版写法)
1. 初始化 Scroll(首次查询,生成快照)
首次查询必须指定 scroll 存活时间,用于维持快照上下文,同时设置 size 指定每页数据量。
GET test_index/_search?scroll=5m { "size": 100, "query": { "match_all": {} } }
返回结果包含关键参数:_scroll_id,后续所有滚动请求依赖该 ID。
2. 滚动分页查询(循环取数)
无需指定索引、查询条件、排序,只需要携带 scroll_id 和续期时间,持续获取下一批数据。
GET _search/scroll { "scroll": "5m", "scroll_id": "上一步返回的_scroll_id" }
循环执行此请求,直到返回的 hits 为空,代表全量数据遍历完毕。
3. 手动清除 Scroll 上下文(重要)
Scroll 快照会常驻内存,超时前不会自动释放,业务结束必须手动清理,防止集群内存泄露。
DELETE _search/scroll { "scroll_id": "对应的_scroll_id" }
四、Scroll 核心特性
-
基于固定快照 :遍历期间索引新增、修改、删除的数据完全不可见,数据一致性强,无漏数、无重复。
-
无深度分页限制 :不受
max_result_window10000 条限制,支持全量数据遍历。 -
无需业务排序字段:Scroll 基于文档内部顺序遍历,不需要依赖高离散排序字段,规避 search_after 字段选型难题。
-
资源占用高:会长时间持有分片快照上下文,占用节点内存、文件句柄,高并发场景压力极大。
-
不支持实时数据:一旦生成快照,无法读取最新业务数据,只适合离线批量任务。
-
不支持跳页:只能向后滚动遍历,无法实现前端页码跳转分页。
五、Scroll 核心优缺点
优点
-
天然保证全量数据一致性,遍历全程数据无错乱、无丢失、无重复。
-
使用简单,无需关心排序字段离散度问题。
-
完美支持超大索引全量导出、数据同步、离线计算场景。
缺点(致命)
-
集群资源开销极大:长期持有分片快照上下文,占用内存,高并发批量导出极易打满 CPU、引发 GC。
-
数据严重滞后:无法感知遍历过程中的数据新增和变更,不适合实时业务。
-
容易资源泄露:代码异常、程序中断时,未手动清理 scroll_id,会导致内存长期占用。
-
官方已废弃:ES7.10+ 版本开始逐步弃用,不再优化维护,被 PIT 方案全面替代。
六、Scroll 淘汰核心原因(面试重点)
很多人只知道 Scroll 不用了,但不知道为什么被 PIT 替代,核心三点:
-
资源模型笨重 :Scroll 的快照是重量级上下文,绑定分片资源,长时间占用集群资源,并发场景扩展性极差。
-
功能固化不灵活:一次初始化固定查询条件和快照,无法动态调整查询参数,无法续期灵活控制。
-
PIT 全方位碾压:PIT 是轻量级时间点视图,资源开销几乎可忽略,同时保留快照一致性能力,还支持动态续期、灵活搭配 search_after,性能和稳定性全面超越 Scroll。
七、Scroll 适用 & 禁用场景
适合场景(仅老旧项目)
-
低并发、低频的离线全量数据导出
-
旧版 ES(7.10 以下)海量数据同步任务
绝对不适用场景
-
前端列表分页、实时查询业务
-
高并发、高频批量任务
-
新版 ES 集群新项目开发
八、Scroll、普通 search_after、PIT+search_after 核心对比
| 分页方案 | 数据一致性 | 资源开销 | 排序依赖 | 适用场景 | 状态 |
|---|---|---|---|---|---|
| Scroll | 极高(快照固定) | 大(重量级上下文) | 无依赖 | 旧版离线全量遍历 | 已废弃 |
| 普通 search_after | 差(实时视图易错乱) | 极小 | 强依赖高离散唯一字段 | 中小数据滚动分页 | 日常常用 |
| PIT+search_after | 极高(时间点快照) | 极小(轻量元数据) | 可依赖内置字段兜底 | 上亿数据、高并发、严谨业务 | 官方最优推荐 |
九、在节点中查看当前获取的scroll快照
GET _nodes/stats/indices/search?pretty 查看这个命令中的
找到字段:
open_contexts:当前节点存活 Scroll 快照数量scroll_total:历史总共创建过多少 scrollscroll_time_in_millis:scroll 累计耗时
这几个字段就可以了。