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

ES深度分页优化

目录
  • 背景和价值
      • 一、核心问题:为什么from/size不适合深度分页?
      • 二、优化方案:按场景选择替代机制
        • 1. 场景:“滚动分页”(Scroll API)—— 适合批量导出/后台任务
        • 2. 场景:“搜索_after”(Search After)—— 适合用户前台分页(支持跳页但需连续)
        • 3. 场景:“预计算分页标记”—— 适合支持随机跳页的业务
        • 4. 场景:“限制最大分页深度”—— 业务层面规避
      • 三、辅助优化:提升分页查询基础性能
      • 四、方案选择决策树
      • 总结
  • 参考资料

背景和价值

Elasticsearch(ES)的深度分页(如查询第1000页以后的数据)会面临性能瓶颈,主要原因是ES的分页机制(from/size)需要在内存中聚合所有匹配结果并排序,当from值过大时(如from=10000),会导致严重的内存消耗和性能下降。优化深度分页需从机制替换查询设计两方面入手,以下是具体方案:

一、核心问题:为什么from/size不适合深度分页?

ES的from/size分页原理是:

  1. 从每个分片查询前from+size条数据;
  2. 将所有分片的结果拉取到协调节点,合并排序后取第fromfrom+size条数据。

from很大时(如from=10000size=10),每个分片需返回10010条数据,协调节点需处理10010×分片数条数据,内存和网络开销呈指数级增长,甚至可能触发OOM(内存溢出)。

二、优化方案:按场景选择替代机制

1. 场景:“滚动分页”(Scroll API)—— 适合批量导出/后台任务

原理:生成一个临时快照(scroll_id),记录查询结果的位置,后续分页通过scroll_id获取下一批数据,避免重复计算。
适用场景:全量数据导出(如导出所有订单)、后台批处理任务(非实时用户交互)。

示例

// 1. 初始化滚动查询,保留快照1分钟
POST /order_index/_search?scroll=1m
{"size": 100,  // 每次返回100条"query": { "match_all": {} },"sort": [{ "order_time": "desc" }]  // 必须指定排序(通常按唯一字段)
}// 2. 后续分页,使用返回的scroll_id
POST /_search/scroll
{"scroll": "1m",  // 延长快照有效期"scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAA...(上一步返回的scroll_id)"
}

优势:性能稳定,支持海量数据分页;
局限

  • 不支持随机跳页(只能顺序翻页);
  • 快照会占用集群资源,需及时清理(DELETE /_search/scroll)。

2. 场景:“搜索_after”(Search After)—— 适合用户前台分页(支持跳页但需连续)

原理:通过上一页最后一条数据的“排序值”作为锚点,查询下一页数据,避免计算from之前的所有数据。
适用场景:用户前台分页(如电商商品列表页),支持“下一页”但不支持“直接跳至第100页”。

示例

// 1. 第一页查询,按order_time和order_id排序(确保唯一排序)
GET /order_index/_search
{"size": 10,"query": { "term": { "user_id": "u300" } },"sort": [{ "order_time": "desc" },{ "order_id": "desc" }  // 用唯一字段作为第二排序,避免排序值重复]
}// 2. 第二页查询,使用第一页最后一条的sort值作为search_after
GET /order_index/_search
{"size": 10,"query": { "term": { "user_id": "u300" } },"sort": [{ "order_time": "desc" },{ "order_id": "desc" }],"search_after": [1622505600000, "order_1000"]  // 第一页最后一条的order_time和order_id
}

优势:性能好(无需计算from前的数据),支持海量数据深度分页;
局限

  • 只能基于上一页的锚点顺序翻页,不支持随机跳页(如从第1页直接跳至第100页);
  • 排序字段必须唯一(通常组合时间+ID,避免数据重复或遗漏)。

3. 场景:“预计算分页标记”—— 适合支持随机跳页的业务

原理:在数据写入时,预先计算分页标记(如按时间/ID范围划分“页”),查询时通过标记直接定位分页位置。
适用场景:需支持随机跳页(如“第100页”)的业务,且数据有明确的排序维度(如按时间递增)。

实现思路

  • 按排序字段(如order_time)将数据分段,每100条记录为一页,记录每页的起始order_timeorder_id
  • 存储分段信息(如在另一个索引pagination_marks中);
  • 查询第N页时,先从pagination_marks获取第N页的起始标记,再用range查询直接定位:
// 查询第100页(假设第100页起始时间为1622505600000,起始ID为order_10000)
GET /order_index/_search
{"size": 100,"query": {"bool": {"must": [{ "term": { "user_id": "u300" } }],"filter": [{ "range": { "order_time": { "lte": 1622505600000 } }  // 基于预计算的标记]}},"sort": [{ "order_time": "desc" },{ "order_id": "desc" }]
}

优势:支持随机跳页,性能接近search_after
局限

  • 需额外存储分页标记,增加写入复杂度;
  • 数据更新(如删除、新增)可能导致标记失效,需定期重建。

4. 场景:“限制最大分页深度”—— 业务层面规避

原理:从业务设计上限制分页深度(如最多支持前100页),超过则提示“数据量过大,请缩小查询范围”。
适用场景:用户实际很少访问深度分页的业务(如搜索引擎通常只显示前100页)。

实现方式

  • 在应用层判断from值,若超过阈值(如from >= 10000),直接返回错误;
  • 引导用户通过筛选条件(如时间范围、分类)缩小查询结果集,减少分页压力。

优势:简单直接,从源头避免深度分页问题;
局限:需业务方接受功能限制。

三、辅助优化:提升分页查询基础性能

无论采用哪种分页机制,以下优化能进一步提升性能:

  1. 合理设计排序字段
    排序字段尽量使用数字型日期型(如order_timeid),避免对text类型字段排序(需额外启用fielddata,内存消耗大)。

  2. 添加查询过滤条件
    减少匹配结果总量(如按时间范围range、用户term过滤),结果集越小,分页压力越小。

  3. 优化索引分片
    分片数量需合理(单分片数据量建议50GB以内),分片过多会增加协调节点的合并开销。

  4. 禁用_source或按需返回字段
    分页查询时,通过_source指定所需字段(如只返回order_idprice),减少数据传输量:

    GET /order_index/_search
    {"_source": ["order_id", "price"],  // 只返回必要字段"size": 10,"from": 100
    }
    

四、方案选择决策树

业务需求 推荐方案 核心原因
批量导出/后台任务 Scroll API 支持全量数据顺序分页
用户前台分页(下一页) Search After 性能好,适合深度分页
必须支持随机跳页 预计算分页标记 平衡跳页需求和性能
可接受功能限制 限制最大分页深度 简单直接,避免性能问题

总结

ES深度分页的核心优化思路是避免使用from/size做深度分页,而是根据业务场景选择:

  • 顺序分页用Search After(用户交互场景)或Scroll API(批量任务);
  • 随机跳页需通过预计算标记在业务层实现;
  • 结合查询过滤、字段裁剪等辅助手段进一步提升性能。

最终目标是:在满足业务需求的前提下,最小化ES的计算和内存开销。

参考资料

http://www.wxhsa.cn/company.asp?id=914

相关文章:

  • 2025年8月国产数据库大事记:东莞银行1078万采购OceanBase、821万采购腾讯TDSQL,2025上半年达梦净利2亿、金仓净利润飙升……
  • VSCode安装Jupyter的常见问题
  • 批量设置Excel样式格式(如:纸张大小,排版,字体等)+ 支持windows系统
  • 张瑜:牛市进程之十大观察指标 - Leone
  • QT-控件使用-获取lable标签宽高尺寸设置图片
  • 初识python:一些基础的知识(推导式)
  • RK3588+preemrt+ethercat搭建
  • Windows 11 系统优化
  • 碎碎念(十六)
  • PK-2600-ALG-2 三同轴转鳄鱼夹测试线应用案例
  • RK3588+xenomai3+ethercat搭建
  • 从英伟达到国产算力:一场必须打赢的“迁移之战”
  • 小说写法分析-个人随记
  • Nuget的不是所配置的源之一
  • part 3
  • 微服务高可用高并发方案
  • Adobe PDF Reader实现旋转PDF功能
  • start.bat
  • 外泌体适配体筛选的 SELEX 技术:5 大核心方法拆解,精准捕捉 “细胞信使”
  • 知识点 AlexNet(2/8)
  • QtCreator问题输出框 MSVC编译出现中文乱码报错
  • Gitee DevOps本土化实践:为中国开发者打造全流程效能引擎
  • pip安装临时使用清华源
  • nginx 企业
  • java毕业设计-基于jspm网上书店管理系统(源码+LW+部署文档+全bao+远程调试+代码讲解等) - 详解
  • redis scan命令替换keys 命令
  • 聊一聊 .NET 某企业ECM内容管理系统 内存暴涨分析
  • SQL之字符串问题大坑
  • 可编辑区域
  • ES 跨订单的详情全局分页 解决