Carry の Blog Carry の Blog
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • OpenClaw
  • Hermes Agent
  • Claude Code
  • MySQL8-SOP手册
  • MySQL实战45讲学习笔记
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carry の Blog

好记性不如烂键盘
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • OpenClaw
  • Hermes Agent
  • Claude Code
  • MySQL8-SOP手册
  • MySQL实战45讲学习笔记
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL

  • Redis

  • Keydb

  • TiDB

  • MongoDB

  • Elasticsearch

    • Elasticsearch 运维知识地图:从安装配置到排障加速恢复
    • Elasticsearch 安装配置
    • 给Elasticsearch集群添加用户密码
    • Elasticsearch 分片和副本:容量怎么规划,改分片数为什么这么麻烦
    • 单节点分片达到默认上限解决办法
    • Elasticsearch集群节点磁盘使用分配不均解决办法
    • Elasticsearch的模板template和映射mapping
    • Elasticsearch 分页查询三种方案:from/size、search_after、scroll 怎么选
      • 1. from + size:适合前几页的常规分页
      • 2. search_after:深分页的正确姿势
      • 3. scroll:批量导出全量数据(不适合用户交互分页)
      • 4. 三种方案怎么选
      • 5. 可复用要点
    • Elasticsearch字符串搜索方式
    • Elasticsearch使用wildcard字段模糊匹配
    • ES数据迁移工具esm
    • Nginx Mirror 模块实现三套ES写入网关
    • ES单机多节点集群docker-compose一键安装
    • ElasticSearch 动态模板 使用方法
    • ES排障两件套:慢查询日志阈值配置 + tcpdump 抓包看真实请求
    • ES 集群恢复太慢?三个参数加速节点/分片恢复
    • Elasticsearch 常用 DSL 语句
    • Logstash迁移ES数据
  • Kafka

  • victoriametrics

  • BigData

  • Sqlserver

  • 数据库
  • Elasticsearch
Carry の Blog
2022-03-17
目录

Elasticsearch 分页查询三种方案:from/size、search_after、scroll 怎么选

版本说明

search_after 与 scroll 在 Elasticsearch 7.x/8.x 均可用,from+size 默认 10000 条的深分页限制自 7.x 起生效。

Elasticsearch 提供三种分页方式,很多人只知道 from/size,但它在深分页场景下会踩到硬限制——理解三者的适用边界,才能在"用户翻页"和"批量导出全量数据"这两类完全不同的场景下选对方案。

# 1. from + size:适合前几页的常规分页

GET my_index/_search
{
  "from": 20,
  "size": 10,
  "query": {
    "match": {
      "title": "elasticsearch"
    }
  }
}
1
2
3
4
5
6
7
8
9
10

from 是结果集的偏移量,size 是每页数量——这个例子从第 20 条开始取 10 条。想按字段排序,加 sort:

GET my_index/_search
{
  "from": 20,
  "size": 10,
  "sort": [
    { "date": { "order": "desc" } },
    "_score"
  ],
  "query": {
    "match": {
      "title": "elasticsearch"
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

先按 date 降序,date 相同时按相关性分数 _score 排序(数组里排序字段有先后优先级)。

为什么深分页会出问题:ES 内部执行分页时,每个分片都要先算出 from + size 条结果再返回给协调节点做全局排序合并,from 越大,每个分片实际计算和传输的数据量就越大。ES 默认把 from + size 的上限设为 10000(index.max_result_window),超过就直接报错——这是刻意的保护机制,防止深分页拖垮集群。from/size 只适合"用户点下一页"这种浅层、随机跳转的分页场景,不适合翻到几千页之后或做全量导出。

# 2. search_after:深分页的正确姿势

GET my_index/_search
{
  "size": 10,
  "query": { "match": { "title": "elasticsearch" } },
  "sort": [
    { "date": "desc" },
    { "_id": "asc" }
  ]
}
1
2
3
4
5
6
7
8
9

拿到这一页最后一条结果的 sort 值(比如 ["2024-01-01", "abc123"]),下一页请求时带上 search_after:

GET my_index/_search
{
  "size": 10,
  "query": { "match": { "title": "elasticsearch" } },
  "sort": [
    { "date": "desc" },
    { "_id": "asc" }
  ],
  "search_after": ["2024-01-01", "abc123"]
}
1
2
3
4
5
6
7
8
9
10

原理:search_after 不依赖 from 偏移量,而是"从上一页最后一条记录的排序值之后继续取",每个分片只需要按排序值定位起点、返回 size 条,不需要像 from+size 那样计算并丢弃前面所有跳过的结果——所以没有 10000 条的深度限制,性能不随页数增加而下降。

坑:sort 里必须包含一个唯一值字段(通常用 _id)作为最后一个排序键,否则当排序字段有重复值时(比如同一天有多篇文章、date 相同),翻页边界会不稳定,可能丢数据或重复数据。search_after 只能"一页一页往后翻",不支持跳页(不能直接跳到第 500 页),这是它相对 from/size 的取舍。

# 3. scroll:批量导出全量数据(不适合用户交互分页)

# 第一次请求,声明游标存活时间
POST my_index/_search?scroll=1m
{
  "size": 1000,
  "query": { "match_all": {} }
}

# 后续用返回的 _scroll_id 持续取下一批
POST _search/scroll
{
  "scroll": "1m",
  "scroll_id": "<上一次返回的 _scroll_id>"
}
1
2
3
4
5
6
7
8
9
10
11
12
13

scroll 会在服务端保留一个类似"数据库快照"的游标,scroll=1m 表示这个游标 1 分钟不用就自动释放。它的语义是"遍历某一时刻的全量快照",即使遍历期间数据在变化,取到的结果也保持遍历开始那一刻的一致性视图。

适用场景:一次性批量导出全部数据(如迁移、离线分析),不适合用户实时点击翻页——因为游标要占用服务端资源持续保持,用户翻页间隔不可控,容易导致大量游标堆积拖累集群。官方现在更推荐用 search_after 配合 Point in Time (PIT) (opens new window) API 替代 scroll 做深度遍历,两者结合既有一致性快照,又没有 scroll 的资源占用问题。

# 4. 三种方案怎么选

方案 适用场景 深分页限制 能否跳页
from + size 用户交互,浅层分页(前几十页内) 有(默认 10000 条) 能
search_after 深分页、导出,需要边界稳定 无 不能,只能顺序翻
scroll 一次性全量遍历(迁移/离线分析) 无 不能

# 5. 可复用要点

  1. from/size 有硬性深度限制(max_result_window 默认 10000),设计分页功能前先判断业务是否可能翻到这个深度。
  2. 需要深分页或大批量顺序遍历,用 search_after,sort 里务必带唯一字段兜底排序稳定性。
  3. 一次性全量导出用 scroll(或更现代的 search_after + PIT),不要把它当成用户交互分页的方案。
#Elasticsearch#搜索引擎
上次更新: 7/29/2026

← Elasticsearch的模板template和映射mapping Elasticsearch字符串搜索方式→

最近更新
01
Nginx 运维知识地图:从配置基础到反向代理实战 原创
07-29
02
MySQL 运维知识地图:从入门配置到高可用排障 原创
07-29
03
单表数据同步方案选型:为什么不该用 mysqldump 做「实时同步」 原创
07-29
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式