Python 操作 Elasticsearch 实现数据翻页的三种方式详解

陆遥
陆遥
发布时间:2026-10-14| 3人浏览过
原创

本文详解 Python 中使用 Elasticsearch 进行数据翻页的三种方式。针对大数据量场景,传统 from+size 浅分页存在性能瓶颈,推荐使用 scroll 滚动查询或 search_after 基于游标的深分页。文章对比了各方案的原理、适用场景及代码实现,帮助开发者解决 ES 集群内存压力与数据一致性难题。

在使用 Elasticsearch 作为搜索引擎提取数据时,若数据规模庞大,采用传统的 from + size 方式无法获取全部结果(默认最大记录数限制为 10000)。这是因为随着页码增加,查询会消耗大量内存,进而导致 ES 集群运行不稳定。为此,Elasticsearch 衍生出了 scroll 和 search_after 等更高效的翻页机制。

from + size 浅分页原理与局限

一、from + size 浅分页

所谓的“浅”分页,即简单的分页逻辑。其原理是:先查询前 20 条数据,然后截断前 10 条,仅返回第 11 至 20 条数据。这种做法实际上浪费了前 10 条数据的查询资源。


GET test/_search
{
 "query": {
 "bool": {
  "filter": [
  {
   "term": {
   "age": 28
   }
  }
  ]
 }
 },
 "size": 10,
 "from": 20,
 "sort": [
 {
  "timestamp": {
  "order": "desc"
  },
  "_id": {
  "order": "desc"
  }
 }
 ]
}

参数 from 定义了目标数据的偏移量,size 定义了当前返回的数据条数。默认情况下,from 为 0,size 为 10,即所有查询默认仅返回前 10 条数据。

有必要了解 from/size 的工作原理:由于 ES 基于分片机制,假设存在 5 个分片,当设置 from=100,size=10 时,ES 会根据排序规则从每个分片中各取回 100 条数据,汇总成 500 条数据后,再从中筛选出最后的 10 条数据返回。

经过测试,越靠后的分页执行效率越低。总体而言,随着 from 值的增加,查询耗时也会随之增加,且数据量越大,这一现象越为明显。

scroll 滚动查询机制

二、scroll 深分页

当 from+size 查询的数据量在 10000 至 50000 条(约 1000 到 5000 页)以内时,该方法尚可接受;但若数据量过大,则会出现深分页问题。为解决上述问题,Elasticsearch 提出了 scroll 滚动查询方式。scroll 类似于 SQL 中的 cursor,每次仅能获取一页内容,并返回一个 scroll_id。通过该 scroll_id 可不断获取下一页内容,因此 scroll 不适用于需要跳页的场景。


# -*- coding: utf-8 -*-
# @Time : 
# @Author :
 
from elasticsearch import Elasticsearch
 
es = Elasticsearch(hosts="ip:9200", timeout=20, max_retries=10, retry_on_timeout=True)
 
# Elasticsearch 需要保持搜索的上下文环境多久 游标查询过期时间为10分钟(10m)
page = es.search(
    index="source_keyword_message", doc_type="source_keyword_message",
    scroll='10m',
    size=100,
    body={
     "query": {"match_all": {}},
    }
   )
# 游标用于输出es查询出的所有结果
sid = page['_scroll_id']
# es查询出的结果总量
scroll_size = page['hits']['total']
# es查询出的结果第一页
datas = page.get('hits').get('hits')
 
while (scroll_size > 0):
  page = es.scroll(scroll_id=sid, scroll='5m')
  sid = page['_scroll_id']
  scroll_size = len(page['hits']['hits'])
  datas = page.get('hits').get('hits')
  
  
  1. 设置 scroll=5m 表示指定 scroll_id 的保留时间为 5 分钟。
  2. 使用 scroll 时必须将 from 设置为 0(默认值即为 0)。
  3. size 参数决定后续每次调用 _search 接口返回的数据数量。

search_after 基于游标的深分页

三、search_after 深分页

官方建议 scroll 方式不应用于实时请求(通常用于数据导出场景),因为每个 scroll_id 不仅占用大量资源,还会生成历史快照,且数据变更不会反映在该快照上。

search_after 分页方式依据上一页的最后一条数据来确定下一页的位置。在分页请求过程中,若索引数据发生增删改查,这些变更会实时反映到游标上。但需注意,由于每一页数据依赖于上一页最后一条数据,因此无法进行跳页请求。

为了定位每一页的最后一条数据,每个文档必须拥有全局唯一值。官方推荐使用 _uid 作为全局唯一标识,实际上使用业务层的 id 亦可。


GET test/_search
{
 "query": {
 "bool": {
  "filter": [
  {
   "term": {
   "age": 28
   }
  }
  ]
 }
 },
 "size": 20,
 "from": 0,
 "sort": [
 {
  "timestamp": {
  "order": "desc"
  },
  "_id": {
  "order": "desc"
  }
 }
 ]
}
  1. 使用 search_after 时必须设置 from=0。
  2. 此处示例使用 timestamp 和 _id 作为唯一值进行排序。
  3. 在返回的最后一条数据中,提取 sort 属性的值,并将其传入 search_after 参数中。

利用 sort 返回的值来搜索下一页数据:


GET test/_search
{
 "query": {
 "bool": {
  "filter": [
  {
   "term": {
   "age": 28
   }
  }
  ]
 }
 },
 "size": 10,
 "from": 0,
 "search_after": [
 1541495312521,
 "d0xH6GYBBtbwbQSP0j1A"
 ],
 "sort": [
 {
  "timestamp": {
  "order": "desc"
  },
  "_id": {
  "order": "desc"
  }
 }
 ]
}

至此,关于 Python 使用 Elasticsearch 实现翻页的三种方式介绍完毕。如需了解更多 Python 与 Elasticsearch 翻页相关内容,请搜索本站往期文章或继续浏览后续文章,感谢大家的支持!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。