首页 > 其他分享 >ElasticSearch中的深度分页问题

ElasticSearch中的深度分页问题

时间:2024-12-17 12:31:01浏览次数:8  
标签:search 分页 深度 查询 ElasticSearch 分片 数据 size

在使用 ElasticSearch 进行搜索时,很多小伙伴会遇到“深度分页”问题。当需要获取大量的分页数据时,查询性能会急剧下降,甚至导致集群负载过高。这篇文章将深入剖析 ElasticSearch 深度分页的成因、危害,并提供一些常用的优化方案。


一、什么是深度分页?

深度分页的定义

在 ElasticSearch 中,我们可以通过 from 和 size 参数进行分页控制:

GET /my_index/_search
{
  "from": 0,
  "size": 10
}
  • from:跳过的记录数
  • size:返回的记录数

例如,from=1000size=10 表示跳过前 1000 条记录,从第 1001 条开始获取 10 条记录。

深度分页就是:

        当 from 参数的值很大时(如 from=10000 以上),ElasticSearch 需要跳过大量数据来获取指定页的内容,这种情况称为深度分页

深度分页的危害

在 ElasticSearch 中,数据是存储在多个分片(Shard)上的,每个分片本质上是一个独立的 Lucene 索引。分页查询会在每个分片上独立执行查询,然后将结果合并和排序。理解深度分页的危害需要从 ElasticSearch 的分布式架构和分片查询流程入手。

分片查询的工作原理

  • 分布式存储
    当一个索引被分配多个分片(例如,5 个分片)时,数据会被均匀分布到不同分片上。每个分片可以分布在不同的节点上。

  • 并行查询
    当进行查询时,ElasticSearch 会将查询请求发送到所有分片,每个分片独立执行查询并返回结果。

  • 结果合并
    收集每个分片返回的结果后,ElasticSearch 在协调节点上进行全局排序和合并,最终返回指定的 fromsize 范围内的结果。

深度分页时分片的执行流程

GET /my_index/_search
{
  "from": 10000,
  "size": 10
}
  • 每个分片分别查询
    每个分片都会独立查询出至少 from + size = 10010 条数据。

  • 本地排序
    每个分片对这 10010 条数据进行排序。

  • 返回数据
    每个分片返回排序后的前 10010 条数据到协调节点。

  • 全局排序与裁剪
    协调节点将所有分片的结果合并,然后进行全局排序,并在这些结果中取第 10000 到 10010 条数据,最终返回给用户。

深度分页的危害剖析

我们分析一下上述过程,这会带来一些什么危害呢

内存消耗急剧增加
  • 分片内存开销
    每个分片需要在内存中加载 from + size 条数据(例如 10010 条)。如果分片较多且数据量庞大,这会导致每个分片消耗大量内存。

  • 协调节点内存开销
    协调节点需要收集所有分片返回的大量数据,并在内存中进行全局排序。这可能导致内存溢出(OOM)。

磁盘和 CPU 负载增加
  • 分片读取开销
    为了跳过大量数据,每个分片必须从磁盘中读取大量文档,增加了 I/O 开销。

  • 排序计算开销
    每个分片需要对大量数据进行排序,然后协调节点需要再进行全局排序,增加了 CPU 计算负担。

查询延迟显著增加
  • 线性增长的延迟
    随着 from 值增大,每个分片需要加载和处理的数据量增多,导致查询延迟线性增加。例如,从第 10000 条开始获取数据的延迟会远高于从第 100 条开始获取数据。
集群稳定性风险
  • 节点压力
    大量内存和 CPU 的消耗会增加分片所在节点的负载,严重时可能导致节点性能下降甚至崩溃。

  • 全局影响
    单个深度分页查询可能拖垮整个集群,影响其他正常查询的性能,降低服务可用性。

二、ES中的深度分页方式

如果使用from、size来实现ES的分页查询,我们将会面临深度分页问题,但是我们又想进行深度分页,ES如何解决呢,我们来看下面两种分页方式

Scroll滚动查询

如何解决深度分页

在 ElasticSearch 中,使用传统的分页方式(from + size)进行深度分页会导致性能急剧下降。比如,当你查询第 10000 页的数据时,from 设置为 999900,这意味着 ElasticSearch 需要扫描前 999900 条记录并将其加载到内存中,再丢弃这些记录,只保留最后 100 条。这种操作不仅浪费大量内存,而且延迟非常高。

Scroll 滚动查询通过引入游标机制数据快照,有效地避免了这种大规模跳过数据带来的性能问题。

举个例子:

假设你需要从一张 100 万条记录的大表中导出所有数据。如果使用传统分页方法(from + size),当你查询第 10000 页时,ElasticSearch 需要先扫描和加载前 999900 条数据,再丢弃它们,仅返回你需要的 100 条数据。这就像每次找第 10000 本书,都要从第 1 本开始数到第 10000 本,既费时又耗力。

而使用 Scroll 滚动查询 就像拥有一个记忆书签,每次查询都会在你停下的地方做个标记,下次直接从这个标记处继续,不需要重新扫描前面的数据。它通过创建一个数据快照(Snapshot),固定查询时的数据状态,并维护一个滚动上下文,保证每次返回数据的同时保存位置,避免重复扫描。

使用方式

初始化滚动查询

GET /my_index/_search?scroll=1m
{
  "size": 100,
  "query": { "match_all": {} }
}
  • scroll=1m:滚动上下文有效期为 1 分钟。
  • size=100:每次返回 100 条记录。

响应如下:

获取下一批数据

GET /_search/scroll
{
  "scroll": "1m",
  "scroll_id": "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAA..."
}

响应也是和上面的响应结构相同,只是返回的scroll_id不同 

清理滚动上下文

完成查询后,及时清理滚动上下文以释放内存:

DELETE /_search/scroll
{
  "scroll_id": "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAA..."
}

优缺点

  • 优点

    • 避免跳过大量数据,性能稳定。
    • 保持数据一致性,适合处理大量数据的场景。
    • 不受 max_result_window 限制,可以获取超过 10000 条的数据。
  • 缺点

    • 内存占用:滚动上下文会占用内存,需要及时释放。
    • 只适用于静态数据:动态更新的数据在滚动过程中不会反映最新变化。
    • 只能向前遍历,不支持随机跳转。

使用场景

  • 数据导出:将索引中的数据批量导出到外部存储。
  • 日志分析:批量分析和处理日志数据。
  • 批处理任务:需要处理大量数据的离线任务,如数据迁移和备份。

滚动查询的工作原理

  1. 创建快照
    第一次查询时,ElasticSearch 为查询结果集创建一个快照,该快照保持数据的一致性,即使在滚动查询过程中有新的数据写入索引,查询结果依然基于快照的数据集,不受新数据影响。

  2. 分批读取
    每次滚动查询返回指定数量的数据(例如 100 条),并生成一个 _scroll_id,作为指向下一批数据的游标。ElasticSearch 会根据这个游标继续从上次结束的位置读取下一批数据,而无需重新扫描前面的数据。

  3. 游标推进
    每次查询会返回新的 _scroll_id,用于后续请求。你只需提供这个 _scroll_id,ElasticSearch 就能知道从哪里继续查找,而不必跳过大量记录。

search_after

如何解决深度分页

search_after 通过使用上一页最后一条记录的排序值来定位下一页的起始点,避免了传统分页需要跳过大量数据的问题。这种方法在需要实时展示大量数据时特别有效。

举个例子:
想象你在一个电子商城里查看商品,商品按价格升序排列。传统的分页就像数到第 10000 个商品,跳过前 9999 个才能展示出来。而 search_after 则是记住第 100 条商品的价格和编号,下次从这个位置直接继续展示第 101 条商品,不用重新扫描前面的商品。

使用方式

第一次查询

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

后续查询

使用上一页最后一条记录的排序值作为 search_after 参数,获取下一页数据。

GET /my_index/_search
{
  "size": 10,
  "sort": [
    { "price": "asc" },
    { "_id": "asc" }
  ],
  "search_after": [ 199.99, "product_12345" ]
}

优缺点

  • 优点

    • 高效分页:避免跳过大量数据,查询性能稳定。
    • 内存占用小:无状态查询,不需要维护上下文。
    • 实时性强:适合动态数据的实时分页。
  • 缺点

    • 只能向前分页:无法跳转到任意页,只能按顺序向前获取数据。
    • 排序要求:必须有唯一的排序字段组合,确保结果的唯一性。

使用场景

  • 实时数据展示:新闻、商品、用户动态等实时数据的分页查询。
  • 日志检索:按时间戳顺序查询和分析日志。
  • 动态数据分析:需要连续获取新数据并按特定顺序排列的场景。

search_after的工作原理

  1. 排序值标记位置
    每次查询结果都会包含排序字段的值(例如 price_id)。search_after 通过这些值标记当前位置,下次查询时从这个位置继续。

  2. 避免跳过数据
    不使用 from 来跳过记录,而是精确地从上次查询的最后位置开始读取。

  3. 无状态查询
    每次查询都是独立的,不需要在服务器上维持上下文,节省内存。

PIT与search_after结合

为什么 search_after 需要配合 PIT(Point in Time)?

直接使用 search_after 进行分页确实可行,但在某些场景下,它有显著的局限性,而引入 PIT(Point in Time) 可以有效解决这些问题。下面我们来详细解释为什么需要结合 PIT,以及它带来的优势。

直接使用 search_after 的问题

  1. 数据不一致性
    如果在分页查询过程中,索引中的数据发生了变化(例如新增、更新或删除文档),每次查询返回的结果可能会受到这些变化的影响,导致数据不一致。

    示例场景

    • 第一次查询:你获取了排序后第 100 条记录,排序字段的值是 timestamp: 2024-06-16T10:00:00
    • 在第二次查询之前:有一条新的记录被插入,排序值正好在你上次获取的记录之前。
    • 第二次查询:当你使用 search_after 进行下一页查询时,结果集可能会跳过或重复某些记录,导致分页不连续。
  2. 并发查询干扰
    当多个查询或数据写入操作并发进行时,直接使用 search_after 的分页请求很容易受到其他操作的干扰,导致分页结果不可预测。

  3. 无法保证长时间分页
    在长时间的分页操作中,数据的变化可能越来越多,导致分页的连续性和完整性无法保证。

PIT(Point in Time)如何解决这些问题

PIT 通过在查询开始时创建一个固定数据视图来解决上述问题。具体来说:

  1. 数据一致性保证

    • 固定视图:PIT 创建时会固定一个数据视图,即使索引中新增、更新或删除了数据,PIT 下的查询结果集不会受到这些变化的影响。
    • 这意味着所有的分页请求都会基于创建 PIT 时的数据快照进行,保证分页结果的连续性和一致性。

    举例说明
    想象你正在看一张快照照片,这张照片捕捉了某一瞬间的所有信息。即使在现实中事物发生了变化,照片里的信息依然保持不变。PIT 就像这样一张数据的快照,让你在分页时始终看到快照时刻的结果。

  2. 避免并发干扰

    • PIT 创建的数据视图是独立的,不会受到其他并发查询或写入操作的干扰。因此,即使在高并发场景下,你的分页查询也能保持稳定。
  3. 长时间分页安全

    • 通过设置合适的 keep_alive 时间(如 1m5m),PIT 可以保持长时间有效,支持长时间的分页操作而不会因为数据变化导致分页结果混乱。

PIT+search_after使用方式

1.创建 PIT 视图
创建一个固定的数据视图,并设置有效期(如 1 分钟):

POST /my_index/_search?keep_alive=1m
{
  "size": 10,
  "sort": [
    { "timestamp": "asc" },
    { "_id": "asc" }
  ]
}

返回的 pit_id 用于后续分页请求。

2.分页查询
使用 pit_idsearch_after 进行分页:

POST /_search
{
  "size": 10,
  "pit": {
    "id": "46ToAwMDaWR...ZmZjZTg",
    "keep_alive": "1m"
  },
  "sort": [
    { "timestamp": "asc" },
    { "_id": "asc" }
  ],
  "search_after": [ "2024-06-16T10:00:00", "record_123" ]
}

3.关闭 PIT 视图
分页完成后,关闭 PIT 释放资源:

DELETE /_pit
{
  "id": "46ToAwMDaWR...ZmZjZTg"
}

标签:search,分页,深度,查询,ElasticSearch,分片,数据,size
From: https://blog.csdn.net/qq_46248151/article/details/144518695

相关文章

  • 深度学习一些基础知识
    1、过拟合问题1、数据增强对图像进行旋转、翻转、裁剪等操作,创造出更多样的数据样本。2、正则化凡是能解决模型泛化误差而不是训练误差的方法,都被称为正则化。模型的泛化误差主要是由模型过拟合引起的,所以正则化的各种方法用于解决模型过拟合的问题。L1和L2正则化:在损失函数......
  • 使用Python实现深度学习模型的分布式训练
    友友们好!我的新专栏《Python进阶》正式启动啦!这是一个专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。在这个专栏中,你将会找到:●深入解析:每一篇文章都将深入剖析Pytho......
  • Vue.js 深度剖析:2024 前端高频面试题详解
    Vue.js深度剖析:2024前端高频面试题详解1.Vue的响应式原理是什么?2.Vue组件通信方式有哪些?3.Vue的生命周期是什么?4.如何优化Vue应用性能?5.什么是Vue的CompositionAPI?6.什么是Vue的VirtualDOM?7.Vuex与Pinia的区别是什么?1.Vue的响应式原理是......
  • 23、Elasticsearch-fielddata内存使用陡增解决方案
    利用searchAfter分页方式代替From-Size查询或Scroll滚动查询,解决From-Size查询存在的深度翻页问题与Scroll滚动查询存在数据量大响应慢的问题。由于searchAfter分页需要保证排序聚合唯一,当使用_id字段进行排序聚合时,可能会导致fielddata内存使用指标陡增,从而导致集群的内存使用率......
  • Docker安装Redis和Elasticsearch
    本章将和大家分享在Docker中如何安装Redis和Elasticsearch。废话不多说,下面我们直接进入主题。一、Docker安装Redis1、拉取最新版的redis镜像dockerpullredis2、查看本地镜像dockerimages3、从官网获取redis.conf配置文件创建并进入指定目录(可自定义)://进入......
  • Elasticsearch、Logstash和Kibana
    ELK概述定义与组成部分:ELK是Elasticsearch、Logstash和Kibana的缩写,这三个工具共同构成了一个强大的日志管理和分析平台。Elasticsearch:是一个分布式的、RESTful风格的搜索和数据分析引擎。它能够存储和索引大量的数据,并提供快速的搜索功能。其核心功能是对数据进行索引,使得......
  • 24-bit 音频 与 16-bit 音频 的对比,主要通过表格形式展示它们的不同:24 bit 是指音频文
    在音频领域,16-bit、24-bit、32-bit和64-bit已经是常见的位深,这些位深代表了音频的动态范围和精度。但如果我们进一步探讨是否存在更高的位深或是否有更高的标准,可以从几个方面来回答。1. 64-bit及更高的位深在理论上,音频位深是没有固定上限的,您可以定义更高的位深,比如128-b......
  • 深度解密企业培训10强:从技术革新到业务落地的实战路径
    如何选取优质的企业培训机构合作伙伴,为企业内部的人才成长与业务升级提供有力支撑。这个选择过程从来不止是简单的“一次采购”或“临时救火”,而更像是长期的、动态演进的人才战略布局——无论是聚焦高管层的战略认知升级,还是面向业务一线的专业技能赋能,企业培训已不再是边缘附......
  • ElasticSearch 常见故障解析与修复秘籍
    文章目录一、ElasticSearch启动服务提示无法使用root用户二、ElasticSearch启动提示进程可拥有的虚拟内存少三、ElasticSearch提示用户拥有的可创建文件描述符太少四、ElasticSearch集群yellow状态分析五、ElasticSearch节点磁盘使用率过高,read_only状态问题解决六、Elas......
  • 电商协作新引擎:在线协作文档工具深度剖析
    在线协作工具如何助力电商团队优化日常运营?在当今竞争激烈的电商行业,效率已成为企业成功的核心要素之一。随着团队规模扩大、跨部门合作需求增长,传统的沟通方式如邮件和聊天工具逐渐显得笨拙和低效。这时候,在线协作工具成为了电商团队提升日常运营效率的关键利器。电商团队的日......