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

news2025/2/24 7:45:11

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

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.coloradmin.cn/o/1576275.html

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

相关文章

2024/4/1—力扣—主要元素

代码实现&#xff1a; 思路&#xff1a;摩尔投票算法 int majorityElement(int *nums, int numsSize) {int candidate -1;int count 0;for (int i 0; i < numsSize; i) {if (count 0) {candidate nums[i];}if (nums[i] candidate) {count;} else {count--;}}count 0;…

【Redis 知识储备】冷热分离架构 -- 分布系统的演进(5)

冷热分离架构 简介出现原因架构工作原理技术案例架构优缺点 简介 引入缓存, 实行冷热分离, 将热点数据放到缓存中快速响应 (如存储到 Redis中) 出现原因 海量的请求导致数据库负载过高, 站点响应再读变慢 架构工作原理 多了缓存服务器, 对于热点数据全部到缓存中, 不常用数…

软考高级:计算机网络概述

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

24.4.7周报

星期一&#xff1a; 再学kmp&#xff0c;学的最明白的一次 贴道kmp的题 洛谷传送门 思路&#xff1a;答案为n-ne【n】&#xff0c;把字符串画两遍理解一下 思路&#xff1a;最长周期&#xff0c;复制一遍过后要求覆盖原字符串&#xff0c;及字符串中…

OpenAI Sora:浅析文生视频模型Sora以及技术原理简介

一、Sora是什么&#xff1f; Sora官方链接&#xff1a;https://openai.com/sora 视频模型领头羊Runway Gen 2、Pika等AI视频工具&#xff0c;都还在突破几秒内的连贯性&#xff0c;而OpenAI&#xff0c;已经达到了史诗级的纪录。 OpenAI&#xff0c;永远快别人一步&#xff0…

Android 11属性系统初始化流程

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

《云原生安全攻防》-- 云原生应用风险分析

为了满足每位朋友的学习需求&#xff0c;并且支持课程的持续更新&#xff0c;本系列课程提供了免费版和付费视频版两种方式来提供课程内容。我们会持续更新课程内容&#xff0c;以确保内容的度和实用性。 在本节课程中&#xff0c;我们将一起探讨云原生应用在新的架构模式下可能…

模块化——如何导入模块?(内置模块与自定义模块)

在Node.js中&#xff0c;要导入另一个模块&#xff0c;我们可以使用require函数。这个函数接受一个文件路径参数&#xff0c;并返回导入的模块。 一、require使用注意事项&#xff1a; (1)自己创建的模块&#xff0c;导入时建议写相对路径&#xff0c;不能省略./和../ //我把…

Struts2:Action类的写法,推荐使用继承ActionSupport类的方法

文章目录 方法一&#xff1a;Action类是一个POJO类&#xff08;简单的Java类&#xff09;ActionDemo2.javastruts_demo2.xmlstruts.xml运行结果其他strutsz_demo1.xml 方法二&#xff1a;实现一个Action的接口ActionDemo2_2.javastruts_demo2.xml运行结果 推荐&#xff01;&…

基于视频监管与AI智能识别技术的水利河道综合治理解决方案

一、方案介绍 TSINGSEE青犀视频水利河道综合治理解决方案是依托视频AI智能分析技术&#xff0c;利用水质/水文等传感器、高清摄像机、水利球、无人机、无人船等感知设备实时采集数据&#xff0c;并与视频能力进行联动&#xff0c;达到智能预警的目的。 TSINGSEE青犀方案以信息…

【单源最短路 图论】882. 细分图中的可到达节点

作者推荐 视频算法专题 本文涉及知识点 单源最短路 图论 LeetCode 882. 细分图中的可到达节点 给你一个无向图&#xff08;原始图&#xff09;&#xff0c;图中有 n 个节点&#xff0c;编号从 0 到 n - 1 。你决定将图中的每条边 细分 为一条节点链&#xff0c;每条边之间…

4月7号总结

java学习 一.正则表达式 定义&#xff1a;正则表达式是一种用于描述字符串模式的表达式&#xff0c;通常被用于文本搜索、匹配和替换。它是一种强大的工具&#xff0c;可以在文本处理和文本分析中进行复杂的匹配和操作。 通过字符串引用里面的方法matches&#xff0c;然后执行…

jupyter python paramiko 网络系统运维

概述 通过使用jupyter进行网络运维的相关测试 设备为H3C 联通性测试 import paramiko import time import getpass import re import os import datetimeusername "*****" password "*****" ip "10.32.**.**"ssh_client paramiko.SSHCli…

相机标定——四个坐标系介绍

世界坐标系(Xw,Yw,Zw) 世界坐标系是一个用于描述和定位三维空间中物体位置的坐标系&#xff0c;通常反映真实世界下物体的位置和方向。它是一个惯性坐标系&#xff0c;被用作整个场景或系统的参考框架。在很多情况下&#xff0c;世界坐标系被认为是固定不变的&#xff0c;即它…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之四 简单视频倒放效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之四 简单视频倒放效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之四 简单视频倒放效果 一、简单介绍 二、简单视频倒放效果实现原理 三、简单视频倒放效果案例实现…

C++搭建深度学习的推理框架

我们的目的是:借助C++搭建一个类似于pytorch,tensorflow的深度学习框架,对标pytorch,tensorflow实现对应的功能。由于本人能力有限,下面本人将借助C++搭建一个简单的全连接神经网络,并且尝试解释里面的算子定义和计算图构建。 算子定义 回顾pytorch里面搭建的全连接神经网…

探索未来游戏:生成式人工智能AI如何重塑你的游戏世界?

生成式人工智能&#xff08;Generative AI&#xff09;正以前所未有的速度改变着各行各业的运作模式。其中&#xff0c;游戏产业作为科技应用的前沿阵地&#xff0c;正经历着前所未有的变革。本文将探讨生成式人工智能如何重塑游戏产业&#xff0c;以及这一变革背后的深远影响。…

Sora是什么?Sora怎么使用?Sora最新案例视频以及常见问题答疑

Sora 是什么&#xff1f; 2024年2月16日&#xff0c;OpenAI 在其官网上面正式宣布推出文本生成视频的大模型Sora 这样说吧给你一段话&#xff0c; 让你写一篇800字的论文&#xff0c;你的理解很可能都有偏差&#xff0c;那么作为OpenAi要做文生视频到底有多难&#xff0c;下面…

Linux设备深探:桥接硬件与软件的秘密通道

在Linux的世界里&#xff0c;"设备"这个词汇比你想象的要丰富和多彩得多。让我们一起来探索Linux设备的奥秘&#xff0c;理解它们是如何在Linux操作系统中发挥作用的。&#x1f427;✨ 1. 什么是Linux设备&#xff1f; 在Linux中&#xff0c;设备被看作是一种特殊的…

Day01-SHELL自动化编程-变量与特殊变量

Day01-SHELL自动化编程-变量与特殊变量 1.编程概述2.课程内容3.Shell编程语言必知必会4.编程语言分类&#xff08;按照执行方式&#xff09;-了解5.编程环境准备6.Shell脚本执行方式6.1概述6.2详解6.2.1 sh或bash6.2.1 .或source6.2.3 相对或绝对路径6.2.4 使用重定向符号执行脚…