当前位置: 首页 > news >正文

Elasticsearch 深分页问题

Elasticsearch 深分页问题

1️⃣ 什么是深分页 (Deep Pagination)

在 Elasticsearch 中,我们可以通过 from + size 进行分页查询:

GET my_index/_search
{"from": 100000,"size": 10
}

这表示 跳过前 100000 条,取 10 条记录
这种情况就属于 “深分页”,因为需要跨过几十万甚至上百万条数据后再取结果。

📌 官方定义:深分页是指 from + size 很大,尤其是 from 很大(如几十万、百万级)。


2️⃣ 为什么深分页有性能问题?

原因 1:ES 基于 Lucene,查询需要拉取全部数据再丢弃

  • Lucene 不支持直接 O(1) 跳过前 N 条。
  • 即使 from=100000 只需要 10 条,ES 仍需:
    1. 从不同的 Shard 拉取 前 100010 条候选文档
    2. score(相关性)排序
    3. 丢掉前 100000 条,只保留最后 10 条

带来的影响:

  • 内存消耗巨大
  • CPU 排序开销大
  • Shard 越多,代价越大(每个分片都要返回 from+size 条数据)

原因 2:分布式聚合 & 排序代价高

假设 5 个分片:

  1. 每个分片返回 from + size 条数据到协调节点(Coordinating Node)
  2. 协调节点合并排序
  3. 丢掉前 from

深分页时,网络传输 & 合并瓶颈显著。

💡 结论from 很大 → 查询性能急剧下降(甚至 OOM)


3️⃣ 官方建议和优化方案

✅ 方案 1:search_after(推荐)

  • 原理:基于上一页最后一条数据的排序值获取下一页
    不用 from,避免重复扫描
  • 缺点:不能直接跳到第 N 页,只能顺序翻页
  • 要求:有唯一且稳定的排序字段(如:时间戳 + _id

第一次请求:

GET my_index/_search
{"size": 10,"sort": [{ "timestamp": "asc" },{ "_id": "asc" }]
}

记住最后一条的 (timestamp, _id)

下一页请求:

GET my_index/_search
{"size": 10,"sort": [{ "timestamp": "asc" },{ "_id": "asc" }],"search_after": [ "2024-06-26T10:00:00Z", "abc123" ]
}

优点

  • 避免全量扫描
  • 性能可控稳定

缺点

  • 只能顺序翻页,不能跳转任意页

✅ 方案 2:scroll API(大批量导出)

  • 用于批量数据导出(不是普通分页展示)
  • 固定查询“快照”,不会随数据变更
  • 持有游标的代价较高

首次查询:

POST my_index/_search?scroll=1m
{"size": 1000,"query": { "match_all": {} }
}

拉取下一批:

POST _search/scroll
{"scroll": "1m","scroll_id": "DxF...abc"
}

✅ 方案 3:Point In Time(PIT)

  • ES 7.10+ 新增
  • 类似 scroll,但轻量,不固定数据快照
  • 一般结合 search_after 使用

创建 PIT:

POST my_index/_pit?keep_alive=1m

✅ 方案 4:业务层优化

  • 限制分页深度(例如最多翻到第 100 页)
  • 改用时间范围 + 条件分页(search_after 按时间+ID 排序更稳定)
  • 建立预聚合/索引表,提前规整数据

4️⃣ 方案对比

方法跳任意页性能场景
from+size小数据量分页
search_after顺序分页大数据
scroll批量导出/全量遍历
PIT+search_after实时数据流式分页

🎯 最佳实践

  • 数据量小(<1w):直接 from+size
  • 大数据 + 顺序翻页search_after
  • 大批量导出scroll
  • 实时数据深翻:PIT + search_after
http://www.dtcms.com/a/332922.html

相关文章:

  • 起落架深孔型腔内轮廓的检测探究 - 激光频率梳 3D 轮廓检测
  • 【0基础3ds Max】学习计划
  • KNN(k近邻算法)
  • vue+flask天气预测可视化系统大数据+机器学习+管理端+爬虫+超酷界面+顶级可视化水平
  • 光学设计鬼像
  • 【RTOS】RT-Thread 进程间通信IPC源码级分析详解
  • 力扣 —— 快慢指针
  • 【Spring Cloud 微服务】1.Hystrix断路器
  • 【LeetCode 热题 100】55. 跳跃游戏
  • 数据结构:严格二叉树 (Strict Binary Tree)
  • 【Twincat3】IO的SCAN 不可选中,SCAN中后扫描不到设备
  • RH134 管理存储堆栈知识点
  • 第20章 LINQ 笔记
  • Akka的容错机制,监督策略与熔断器的区别
  • 【时时三省】(C语言基础)共用体类型
  • 深度解析 DDoS 攻击:运作机制与防御体系构建​
  • 金融项目高可用分布式TCC-Transaction(开源框架)
  • 01数据结构-拓扑排序
  • Go语言实战案例:静态资源服务(CSS、JS、图片)
  • 迁移学习的常见研究领域(附有相关资料)
  • Kubernetes(2)pod的管理及优化
  • 数据结构初阶(17)排序算法——非比较排序、排序算法总结
  • LintCode第107题-单词拆分-新版
  • 国产操作系统之openEuler:根深叶茂
  • 力扣习题:基本计算器
  • 通过CANopen 配置闭环驱动器C5-E——易格斯igus
  • platform总线注册流程分析
  • CUDA 编程笔记:使用 CUDA 加速数组总和
  • 102、【OS】【Nuttx】【周边】文档构建渲染:安装 Esbonio 服务器
  • 【JavaEE】多线程 -- 死锁问题