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;数据分片 数据分片指按照某个维度将存放在单一数据库中的数据分散地存…

每天学习一个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直聘、五…

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

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

jest单元测试——项目实战

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

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

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

Android 11属性系统初始化流程

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

智能网联汽车自动驾驶数据记录系统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;并且这些算法中也会涉及多种优化措施…

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

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

移动平台相关(安卓)

目录 安卓开发 Unity打包安卓 ​编辑​编辑 BuildSettings PlayerSettings OtherSettings 身份证明 配置 脚本编译 优化 PublishingSettings 调试 ReMote Android Logcat AndroidStudio的调试 Java语法 ​编辑​编辑​编辑 变量 运算符 ​编辑​编辑​编辑​…

面向低碳经济运行目标的多微网能量互联优化调度matlab程序

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 运用平台 matlabgurobi 程序简介 该程序为多微网协同优化调度模型&#xff0c;系统在保障综合效益的基础上&#xff0c;调度时优先协调微网与微网之间的能量流动&#xff0c;将与大电网的互联交互作为备用…

百度松果菁英班——机器学习实践四:文本词频分析

飞桨AI Studio星河社区-人工智能学习与实训社区 &#x1f96a;jieba分词词频统计 import jieba # jieba中文分词库 ​ with open(test.txt, r, encodingUTF-8) as novelFile:novel novelFile.read() # print(novel) stopwords [line.strip() for line in open(stop.txt, r,…

初识C++ · 类和对象(上)

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 4.1 访问限定符 4.2 封装 5.类的作用域 6.类的实例化 7.类的对象大小的计算 8.类成员函数的this指针 1.面向过程和面向对象初步认识 C语言是一门面向过程的语言&#xff0c;注重的…

vue+springboot多角色登录

①前端编写 将Homeview修改为manager Manager&#xff1a; <template><div><el-container><!-- 侧边栏 --><el-aside :width"asideWidth" style"min-height: 100vh; background-color: #001529"><div style"h…

百度文库验证码识别

一、前言 百度出了如图所示的验证码&#xff0c;需要拖动滑块&#xff0c;与如图所示的曲线轨迹进行重合。经过不断研究&#xff0c;终于解决了这个问题。我把识别代码分享给大家。 下面是使用selenium进行验证的&#xff0c;这样可以看到轨迹滑动的过程&#xff0c;如果需要…

亚马逊店铺引流:海外云手机的利用方法

在电商业务蓬勃发展的当下&#xff0c;亚马逊已经成为全球最大的电商平台之一&#xff0c;拥有庞大的用户群和交易量。在激烈的市场竞争中&#xff0c;如何有效地吸引流量成为亚马逊店铺经营者所关注的重点。海外云手机作为一项新兴技术工具&#xff0c;为亚马逊店铺的流量引导…