ES入门十五:分页的三驾马车【from+size、search after、scroll api】

从数据集中获取数据时分页是绕不开的操作,一下子从数据集中获取过多的数据可能会造成系统抖动、占用带宽等问题。特别是进行全文搜索时,用户只关心相关性最高的那个几个结果,从系统中拉取过多的数据等于浪费资源。

ES提供了3种分页方式:

  1. from + size: 最普通、简单的分页方式,但是会产生深分页的问题
  2. search after: 解决深分页的问题,但只能一页页地往下翻,不支持跳到指定页数
  3. scroll Api: 会创建数据快照,无法检索新写入的数据,适合对结果集进行遍历的时候

这3种方式的分页操作都有其优缺点,适合不同的场合使用。今天我们就来学习这3种分页方式,但除了学习这3种分页方式外,我们还会介绍ES新引入的特性:Point In Time,看看如何使用Point In Time+search after的方式来代替scroll Api进行大量数据的导出

from +size 分页操作与深分页问题

在我们检索数据时,系统会对数据相关性算分进行排序,然后默认返回前10条数据。我们可以使用from +size来指定获取哪些数据。其使用示例如下:

# 简单的分页操作
GET books/_search
{"from": 0, # 指定开始位置"size": 10, # 指定获取文档个数"query": {"match_all": {}}
}

如上示例,使用“from”指定获取数据的开始位置,使用“size”指定获取文档带的个数

但当我们将from设置大于10000或者size设置大于10001的时候,这个查询将会报错:

# 返回结果中的部分错误信息
......
"root_cause" : [{"type" : "illegal_argument_exception","reason" : "Result window is too large, from + size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."}
],
"type" : "search_phase_execution_exception",
"reason" : "all shards failed",
"phase" : "query",
"grouped" : true,
......

从报错信息可以看出,我们要获取的数据集合太大了,系统拒绝了我们的请求。我们可以使用“index.max_result_window”配置项设置这个上限:

PUT books/_settings
{"index": {"max_result_window": 20000}
}

如上示例,我们设置了这个上限为20000。虽然使用这个配置有时候可以解决燃眉之急,但是这个上限设置过大的情况下会产生非常严重的问题,因为ES会存在深分页的问题

那为什么时深分页和为什么会产生深分页的问题那?
image.png
如上图,ES把数据保存在3个主分片中,当使用from=90 和size=10进行分页的时候,ES会从每个分片中分别获取100个文档,然后把这300个文档在汇聚到协调节点中进行排序,最后选出排序后的前100个文档,返回第90到99的文档

可以看到,当页数变大(发生了深分页)的时候,在每个分片中获取的数据越多,消耗的资源就越多。并且如果分片越多,汇聚到协调节点的数据越多,最终协调到协调节点的文档数为:shard_acount *(from + size)

search after

使用search after api可以避免产生深分页的问题,不过 search after 不支持跳转到指定页面,只能一页页的往下翻

使用 search after接口分为两步:

  1. 在sort中指定需要排序的字段,并且保证其值的唯一性(可以使用文档的id)
  2. 在下一次查询时,带上返回结果的最后一个文档的sort值进行访问

search after的使用示例如下:

# 第一次调用 search after
POST books/_search
{"size": 2,"query": { "match_all": {} },"sort": [{ "price": "desc" },{ "_id": "asc" }]
}# 返回结果
"hits" : [{"_id" : "6","_source" : {"book_id" : "4ee82467","price" : 20.9},"sort" : [20.9, "6"]},{"_id" : "1","_source" : {"book_id" : "4ee82462","price" : 19.9},"sort" : [19.9, "1"]}
]

如上示例,在第一次调用search after时指定了sort的值,并且sort中指定了price 倒序排序。为了保证排序的唯一性,我们指定了文档_id作为唯一值

可以看到,第一次调用的返回结果除了文档的信息外,还有sort相关的信息,在下一次调用的时候需要带上最后一个文档的sort值,示例中其值为:[19.9, “1”]。

下面的示例是第二次调用search after 接口进行翻页操作:

# 第二次调用 search after
POST books/_search
{"size": 2,"query": {"match_all": {}},"search_after":[19.9, "1"], # 设置为上次返回结果中最后一个文档的 sort 值"sort": [{ "price": "desc" },{ "_id": "asc" }]
}

如上示例,进行翻页操作的时候在search after字段中设置上一次返回结果中最后一个文档的sort值,并且保持sort的内容不变

那为啥search after不会产生深度分页的问题那?其关键就是sort中指定的唯一排序值
image.png
如上图,因为有了唯一的排序值做保证,所以每个分片只需要返回比sort中唯一值大的size个数据即可。例如,上一次的查询返回的最后一个文档的sort为a,那么这一次查询只需要在分片1,2,3中返回size个排序比a大的文档,协调节点汇总这些数据进行排序后返回size个结果给客户端

而from + size的方式因为没有唯一值,所以没法保证每个分片上的排序就是全局的排序,必须把每个分片的from+size个数据汇总到协调节点进行排序处理,导致出现了深分页的问题

因为sort的值是根据上一次请求结果来设置的,所以search after不支持跳转到指定的页数,甚至不能返回前一页,只能一页页往下翻。当我们可以结合缓存中间件,把每页返回的sort值缓存下来,实现往前翻页的功能

scroll Api

当我们相对结果集进行排序的时候,例如做全量数据导出时,可以使用scroll Api。scroll Api会创建数据快照,后续的访问将会基于这个快照来进行,所以无法检索新写入的数据。
scroll API 的使用示例如下:

# 第一次使用 scroll API
POST books/_search?scroll=10m
{"query": {"match_all": {}},"sort": { "price": "desc" }, "size": 2
}# 结果
{"_scroll_id" : "FGluY2x1ZGVfY29udGV4dF9......==","hits" : {"hits" : [{"_id" : "6","_source" : {"book_id" : "4ee82467","price" : 20.9}},......]}
}

如上示例,在第一次使用scroll Api需要初始化scroll 搜索并且创建快照,使用scroll查询参数指定本次“查询上下文(快照)”的有效时间,本示例中为10分钟。

其返回的结果中除了匹配文档的列表外还有_scroll_id, 我们需要在翻页的请求带上这个_scroll_id:

# 进行翻页
POST /_search/scroll                                                    
{"scroll" : "5m",   "scroll_id" : "FGluY2x1ZGVfY29udGV4dF9......==" 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/799308.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java | Leetcode Java题解之第15题三数之和

题目&#xff1a; 题解&#xff1a; class Solution {public List<List<Integer>> threeSum(int[] nums) {int n nums.length;Arrays.sort(nums);List<List<Integer>> ans new ArrayList<List<Integer>>();// 枚举 afor (int first 0;…

springboot整合ShardingSphere分库分表并插入1kw条记录

目录 一&#xff0c;数据分片 二&#xff0c;水平分片 三&#xff0c;创建数据库表 四&#xff0c;springboot项目导入依赖 五&#xff0c;创建类 六&#xff0c;bug bug放到最后了。 一&#xff0c;数据分片 数据分片指按照某个维度将存放在单一数据库中的数据分散地存…

数据结构 实验报告11

一、实验目的和要求 目的&#xff1a;熟悉后序线索二叉树并实现后序遍历 要求&#xff1a; &#xff08;1&#xff09;创建二叉树。 &#xff08;2&#xff09;转换为后序线索二叉树。 &#xff08;3&#xff09;实现后序遍历的非递归算法。 二、实验环境 编译器&#xf…

每天学习一个Linux命令之curl

每天学习一个Linux命令之curl 在Linux系统中&#xff0c;有很多有用的命令可以帮助我们与网络进行交互。一个非常常用的命令是curl&#xff0c;它是一个功能强大的工具&#xff0c;可用于发送、接收和处理各种网络请求。本文将详细介绍在Linux下使用curl命令的各种选项及其用法…

如何理解图像处理领域的病态问题(ill-posed problem)

ill-posed problem&#xff0c;我们可以理解为病态问题或者不适定问题。在本文中&#xff0c;统一成为不适定问题。 在讨论不适定问题&#xff08;ill-posed problem&#xff09;之前&#xff0c;我们先来看一下什么叫适定性问题&#xff08;well-posed problem&#xff09;。…

如何明确的选择IT方向?

一、明确目标 作为初学者&#xff0c;先树立自己目标&#xff0c;找到自己感兴趣的IT行业&#xff0c;IT行业分很多种&#xff0c;听的最多次的无非不就是web前端工、程序员、后端、大数据、网络运维等。学习知识也是为了找到更好的工作&#xff0c;所以我建议先去boss直聘、五…

浅谈Mysql(四)——Mysql知识补充

一、mysql什么时候会锁表 MySQL中的查询语句通常不会锁表&#xff0c;因为查询操作只读取数据而不修改数据。然而&#xff0c;当执行某些特定的查询语句或者在特定情况下&#xff0c;MySQL可能会对表进行锁定以保证数据的一致性和完整性。以下是几种可能导致表锁定的情况&#…

目标检测标签分配策略,难样本挖掘策略

在目标检测任务中&#xff0c;样本的划分对于模型的性能具有至关重要的影响。其中&#xff0c;正样本指的是包含目标物体的图像或区域&#xff0c;而负样本则是不包含目标物体的图像或区域。然而&#xff0c;在负样本中&#xff0c;有一部分样本由于其与正样本在特征上的相似性…

jest单元测试——项目实战

jest单元测试——项目实战 一、纯函数测试二、组件测试三、接口测试四、React Hook测试&#x1f4a5; 其他的疑难杂症另&#xff1a;好用的方法 &#x1f31f; 温故而知新&#xff1a;单元测试工具——JEST 包括&#xff1a;什么是单元测试、jest的基本配置、快照测试、mock函数…

机器学习工作流

本文的目的是演示如何构建一个相对完整的机器学习工作流 1.首先对工程进行基本的参数配置 # 进行建模基本配置 SCORE_EVA roc_auc random_state_clf 1 n_jobs 4 cv_split StratifiedKFold(n_splits5, shuffleTrue, random_state1) cv_split2 StratifiedKFold(n_splits5, …

(013)window的Idea运行程序 Amazon java.nio.file.AccessDeniedException

解决方法一 在资源管理器中删除该目录&#xff0c; 在程序中使用代码&#xff0c;重新建立该目录&#xff1a; if (!FileUtil.exist(destinationPath)){FileUtil.mkdir(destinationPath); }解决方法二 JDK 的版本有问题&#xff0c;换个JDK。 解决方法三 网络不好&#xf…

「39」打造专业流畅的直播特效转场……

「39」工作室模式 打造专业流畅的直播特效转场体验 工作室模式是OBS软件里的一个特殊功能,用于后期直播过程中追求直播效果的用户,才会使用此功能。 该功能意在更加平滑,使用模板信息变化的过渡效果。主要用在赛事比分、活动抽奖、直播时需要经常更改的场景和内容,以及片…

Spring之底层架构核心概念解析

你好&#xff0c;我是柳岸花开。 在当今快速发展的软件开发领域&#xff0c;各种技术层出不穷&#xff0c;但有一项技术以其卓越的设计、灵活的配置和广泛的应用&#xff0c;始终屹立在开发者的工具箱中——这就是Spring框架。自2003年首次发布以来&#xff0c;Spring已经成为J…

Android 11属性系统初始化流程

在init进程启动的第二阶段&#xff0c;调用PropertyInit 对属性系统进行初始化 int SecondStageMain(int argc, char** argv) {//省略PropertyInit();//省略 }PropertyInit函数在system\core\init\property_service.cpp 中实现 void PropertyInit() {//省略mkdir("/dev/…

opencv x86(32位) windows下vs2019编译问题

opencv x86(32位) windows下vs2019编译相关资料很多&#xff0c;都特别受用。例如 - https://blog.csdn.net/m0_59025104/article/details/134109081 - https://blog.csdn.net/sements/article/details/108410470 但是&#xff0c;自己编译时候仍遇到一些问题&#xff0c;例如&…

智能网联汽车自动驾驶数据记录系统DSSAD数据元素

目录 第一章 数据元素分级 第二章 数据元素分类 第三章 数据元素基本信息表 表1 车辆及自动驾驶数据记录系统基本信息 表2 车辆状态及动态信息 表3 自动驾驶系统运行信息 表4 行车环境信息 表5 驾驶员操作及状态信息 第一章 数据元素分级 自动驾驶数据记录系统记录的数…

【GameFi】 链游 | Brilliantcrypto点火活动

活动&#xff1a;https://app.galxe.com/quest/brilliantcrypto/GCt8wthq2J Brilliantcrypto点火活动正在Galxe上进行 &#x1f389; 活动时间&#xff1a;2024/04/06 12:00 ~ 2024/05/04 12:00 奖励总价值1200美元的MATIC 完成任务並在Brilliantcrypto Galxe Space上赚取积分。…

【数据结构与算法】:快速排序和冒泡排序

一&#xff0c;快速排序 快速排序是一种比较复杂的排序算法&#xff0c;它总共有4种实现方式&#xff0c;分别是挖坑法&#xff0c;左右"指针"法&#xff0c;前后"指针"法&#xff0c;以及非递归的快速排序&#xff0c;并且这些算法中也会涉及多种优化措施…

Docker是一个开源的应用容器引擎

Docker是一个开源的应用容器引擎&#xff0c;它让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何Linux或Windows操作系统的机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口。Docker技术的…

zdpdjango_materialadmin使用Django开发一个Material风格的后台管理系统

启动项目 同样地&#xff0c;还是先看看代码&#xff1a; 将项目启动起来&#xff1a; 浏览器访问&#xff1a;http://localhost:8000/ 代码初步优化 首先是将admin_materal提到本地来&#xff1a; 移除掉第三方依赖&#xff1a; pip uninstall django-admin-materi…