Elasticsearch深度分页问题

目录

什么是深度分页

深度分页会带来什么问题

深度分页问题的常见解决方案

滚动查询:Scroll Search

search_after

总结


什么是深度分页

分页问题是Elasticsearch中最常见的查询场景之一,正常情况下分页代码如实下面这样的:

# 查询第一页5条数据
GET /user/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 5  
}

        但是如果我们查询的数据页数特别大,当from + size大于10000的时候,就会出现问题,如下图报错信息所示:

       ES通过参数index.max_result_window用来限制单次查询满足查询条件的结果窗口的大小,其默认值为10000。


深度分页会带来什么问题

ES分页查询流程大致如下:

1. 数据存储在各个分片中,协调节点将查询请求转发给各个节点,当各个节点执行搜索后,将排序后的前N条数据返回给协调节点。

2. 协调节点汇总各个分片返回的数据,再次排序,最终返回前N条数据给客户端。

3. 这个流程会导致一个深度分页的问题,也就是翻页越多,性能越差,甚至导致ES出现OOM。

在分布式系统中,对结果排序的成本随分页的深度成指数上升。

从10万名高考生中查询成绩为的10001-10100位的100名考生的信息。

       可以看出,每次有序的查询都会在每个分片中执行单独的查询,然后进行数据的二次排序,而这个二次排序的过程是发生在heap中的,也就是说当你单次查询的数量越大,那么堆内存中汇总的数据也就越多,对内存的压力也就越大。这里的单次查询的数据量取决于你查询的是第几条数据而不是查询了几条数据,比如你希望查询的是第10001-10100这一百条数据,但是ES必须将前10100全部取出进行二次查询。因此,如果查询的数据排序越靠后,就越容易导致OOM(Out Of Memory)情况的发生,频繁的深分页查询会导致频繁的FGC。

       ES为了避免用户在不了解其内部原理的情况下而做出错误的操作,设置了一个阈值,即max_result_window,其默认值为10000,其作用是为了保护堆内存不被错误操作导致溢出。


深度分页问题的常见解决方案

尝试避免使用深度分页

        解决深度分页问题最好的办法就是避免使用深度分页。谷歌、百度目前作为全球和国内做大的搜索引擎不约而同的在分页条中删除了“跳页”功能,其目的就是为了避免用户使用深度分页检索。

       淘宝虽然没有删除“跳页”功能,但不管我们搜索什么内容,只要商品结果足够多,返回的商品列表都是仅展示前100页的数据,其本质和ES中的max_result_window作用是一样的,都是限制你去搜索更深页数的数据。手机端APP就更不用说了,直接是下拉加载更多,连分页条都没有,相当于你只能点击“下一页”。

滚动查询:Scroll Search

        scroll滚动搜索是先搜索一批数据,然后下次再搜索下一批数据,以此类推,直到搜索出全部的数据来。

        scroll搜索会在第一次搜索的时候,保存一个当时的视图快照,之后只会基于该视图快照搜索数据,如果在搜索期间数据发生了变更,用户是看不到变更的数据的。因此,滚动查询不适合实时性要求高的搜索场景。

官方已不推荐使用滚动查询进行深度分页查询,因为无法保存索引状态。

适合场景

单个滚动搜索请求中检索大量结果,即非“C端业务”场景

使用

第一次进行scroll查询:

#查询命令中新增scroll=1m,说明采用游标查询,保持游标查询窗口1分钟,也就是本次快照的结果缓存起来的有效时间是1分钟。
GET /user/_search?scroll=1m 
{
    "query": { "match_all": {}},
    "size":  2
}

查询结果:除了返回前2条记录,还返回了一个游标ID值_scroll_id。

从第二次查询开始,每次查询都要指定_scroll_id参数:

       多次根据scroll_id游标查询,直到没有数据返回则结束查询。采用游标查询索引全量数据,更安全高效,限制了单次对内存的消耗。

删除游标scroll

       scroll超过超时后,搜索上下文会自动删除。然而,保持scroll打开是有代价的,因此一旦不再使用,就应明确清除scroll上下文。

DELETE /_search/scroll
{
    "scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFk9COHR0V19kU3plamJEWWhEbTF3V0EAAAAAAACvYRZDRS0zRUZ2eVNmTzhKdTQ2VjAtenV3"
}

注意事项

1. scroll滚动查询不适合实时性要求高的查询场景,比较适合数据迁移的场景。

2. scroll查询完毕后,要手动清理掉 scroll_id。虽然ES有自动清理机制,但是 srcoll_id 的存在会耗费大量的资源来保存一份当前查询结果集映像,并且会占用文件描述符。

       官方建议:ES7之后,不再建议使用scroll API进行深度分页。如果要分页检索超过 Top 10,000+ 结果时,推荐使用:PIT + search_after。


search_after

       scroll API适用于高效的深度滚动,但滚动上下文成本高昂,不建议将其用于实时用户请求。而search_after参数通过提供一个活动光标来规避这个问题。这样可以使用上一页的结果来帮助检索下一页。

search_after 分页查询可以简单概括为如下几个步骤:

1. 获取索引的pit

       使用 search_after 需要具有相同查询和排序值的多个搜索请求。如果在这些请求之间发生刷新,结果的顺序可能会发生变化,从而导致跨页面的结果不一致。为防止出现这种情况,可以创建一个时间点 (PIT) 以保留搜索中的当前索引状态。Point In Time(PIT)是 Elasticsearch 7.10 版本之后才有的新特性。

# 创建一个时间点(PIT)来保存搜索期间的当前索引状态
POST /user/_pit?keep_alive=1m
#返回结果,会返回一个PID的值
{
  "id" : "39K1AwEEdXNlchY5anUxTHFxelJJLURrR0xMb2RtTFBnABZDRS0zRUZ2eVNmTzhKdTQ2VjAtenV3AAAAAAAAALGMFk9COHR0V19kU3plamJEWWhEbTF3V0EAARY5anUxTHFxelJJLURrR0xMb2RtTFBnAAA"
}

2. 根据pit首次查询

根据pit查询的时候,不用指定索引的名词。

GET /_search
{
  "query": {
        "match_all": {}
    },
  "pit": {
        "id":  "39K1AwEEdXNlchY5anUxTHFxelJJLURrR0xMb2RtTFBnABZDRS0zRUZ2eVNmTzhKdTQ2VjAtenV3AAAAAAAAALGMFk9COHR0V19kU3plamJEWWhEbTF3V0EAARY5anUxTHFxelJJLURrR0xMb2RtTFBnAAA", 
        "keep_alive": "1m"
  },
  "size": 2, 
  "sort": [
        {"_id": "asc"}    
    ]
}

返回结果:

根据search_after和pit进行翻页查询

       要获得下一页结果,请使用最后一次命中的排序值(包括 tiebreaker)作为 search_after 参数重新运行先前的搜索。如果使用 PIT,请在 pit.id 参数中使用最新的 PIT ID。搜索的查询和排序参数必须保持不变。

#search_after指定为上一次查询返回的sort值。
GET /_search
{
  "query": {
        "match_all": {}
    },
  "pit": {
        "id":  "39K1AwEEdXNlchY5anUxTHFxelJJLURrR0xMb2RtTFBnABZDRS0zRUZ2eVNmTzhKdTQ2VjAtenV3AAAAAAAAALGMFk9COHR0V19kU3plamJEWWhEbTF3V0EAARY5anUxTHFxelJJLURrR0xMb2RtTFBnAAA", 
        "keep_alive": "1m"
  },
  "size": 2, 
  "sort": [
        {"_id": "asc"}    
    ],
  "search_after": [                                
    3
  ]
}

总结

分页方式

性能

优点

缺点

适用场景

from + size

灵活性好,实现简单,支持随机翻页

受制于max_result_window设置,不能无限制翻页;

存在深度翻译问题,越往后翻译越慢。

数据量比较小,能容忍深度分页问题

scroll

解决了深度分页问题

scroll查询的相应数据是非实时的,如果遍历过程中插入新的数据,是查询不到的;

保留上下文需要足够的堆内存空间。

海量数据的导出,需要查询海量结果集的数据

search_after

性能最好,不存在深度分页问题,能够反映数据的实时变更

实现复杂,需要有一个全局唯一的字段连续分页的实现会比较复杂,因为每一次查询都需要上次查询的结果,它不适用于大幅度跳页查询

海量数据的分页

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ps:堆栈模式在摄影后期的应用

Photoshop 的堆栈模式 Stack Mode为摄影师提供了一种强大的后期处理能力,通过堆叠和处理多张照片来实现无法单靠一张照片完成的效果。 正确的前期拍摄策略和后期处理技巧可以显著提高最终图像的质量和视觉冲击力。 ◆ ◆ ◆ 前期拍摄通用注意事项 在前期拍摄时&am…

【Linux学习】线程互斥与同步

目录 二十.线程互斥 20.1 什么是线程互斥? 20.2 为什么需要线程互斥? 20.3 互斥锁mutex 20.4 互斥量的接口 20.4.1 互斥量初始 20.4.2 互斥量销毁 20.4.3 互斥量加锁 20.4.4 互斥量解锁 20.4.5 互斥量的基本原理 20.4.6 带上互斥锁后的抢票程序 20.5 死锁问题 死锁…

【医学大模型 动态知识图谱】AliCG概念图 = 知识图谱 + 实时更新、细粒度概念挖掘、个性化适应

AliCG概念图 提出背景能力强化细粒度概念获取长尾概念挖掘分类体系进化对比传统知识图谱 部署方法如何提高信息检索的质量?如何在神经网络中学习概念嵌入?如何在预训练阶段利用概念图? 提出背景 论文: https://arxiv.org/pdf/2106.01686.pdf…

论文解读:MobileOne: An Improved One millisecond Mobile Backbone

论文创新点汇总:人工智能论文通用创新点(持续更新中...)-CSDN博客 论文总结 关于如何提升模型速度,当今学术界的研究往往聚焦于如何将FLOPs或者参数量的降低,而作者认为应该是减少分支数和选择高效的网络结构。 概述 MobileOne(≈MobileN…

《剑指Offer》笔记题解思路技巧优化 Java版本——新版leetcode_Part_2

《剑指Offer》笔记&题解&思路&技巧&优化_Part_2 😍😍😍 相知🙌🙌🙌 相识🍓🍓🍓广度优先搜索BFS🍓🍓🍓深度优先搜索DF…

九、java 继承

文章目录 java 继承3.1 根父类Object3.2 方法重写3.3 继承案例:图形类继承体系3.4 继承的细节3.4.1 构造方法3.4.2 重名与静态绑定3.4.3 重载和重写3.4.4 父子类型转换3.4.5 继承访问权限protected3.4.6 可见性重写3.4.7 防止继承final 3.5 继承是把双刃剑3.5.1 继承…

70.SpringMVC怎么和AJAX相互调用的?

70.SpringMVC怎么和AJAX相互调用的&#xff1f; &#xff08;1&#xff09;加入Jackson.jar&#xff08;2&#xff09;在配置文件中配置json的消息转换器.(jackson不需要该配置HttpMessageConverter&#xff09; <!‐‐它就帮我们配置了默认json映射‐‐> <mvc:anno…

Netty应用——实例-群聊系统(十六)

编写一个Netty群聊系统&#xff0c;实现服务器端和客户端之间的数据简单通讯 (非阻塞)实现多人群聊服务器端:可以监测用户上线&#xff0c;离线&#xff0c;并实现消息转发功能客户端:通过channel可以无阳塞发送消息给其它所有用户&#xff0c;同时可以接受其它用户发送的消息(…

哈夫曼树的学习以及实践

哈夫曼树 哈夫曼树的基本了解哈夫曼树的基本概念创建霍夫曼树的思路编码构建的思路代码实现创建HuffmanTree结点初始化HuffmanTree创建霍夫曼树霍夫曼树编码 哈夫曼树的基本了解 给定 n 个 权值 作为 n 个 叶子节点&#xff0c;构造一颗二叉树&#xff0c;若该树的 带权路径长…

C语言第二十三弹---指针(七)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1、sizeof和strlen的对比 1.1、sizeof 1.2、strlen 1.3、sizeof 和 strlen的对比 2、数组和指针笔试题解析 2.1、⼀维数组 2.2、二维数组 总结 1、si…

C语言每日一题(56)平衡二叉树

力扣网 110 平衡二叉树 题目描述 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,…

牛客错题整理——C语言(实时更新)

1.以下程序的运行结果是&#xff08;&#xff09; #include <stdio.h> int main() { int sum, pad,pAd; sum pad 5; pAd sum, pAd, pad; printf("%d\n",pAd); }答案为7 由于赋值运算符的优先级高于逗号表达式&#xff0c;因此pAd sum, pAd, pad;等价于(…

Linux系统之部署File Browser文件管理系统

Linux系统之部署File Browser文件管理系统 一、File Browser介绍1.1 File Browser简介1.2 File Browser功能1.3 File Browser使用场景 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本 四、安装File Browser4…

Linux_线程

线程与进程 多级页表 线程控制 线程互斥 线程同步 生产者消费者模型 常见概念 下面选取32位系统举例。 一.线程与进程 上图是曾经我们认为进程所占用的资源的集合。 1.1 线程概念 线程是一个执行分支&#xff0c;执行粒度比进程细&#xff0c;调度成本比进程低线程是cpu…

SpringCloud-Eureka服务注册中心测试实践

5. Eureka服务注册中心 5.1 什么是Eureka Netflix在涉及Eureka时&#xff0c;遵循的就是API原则.Eureka是Netflix的有个子模块&#xff0c;也是核心模块之一。Eureka是基于REST的服务&#xff0c;用于定位服务&#xff0c;以实现云端中间件层服务发现和故障转移&#xff0c;服…

fast.ai 深度学习笔记(六)

深度学习 2&#xff1a;第 2 部分第 12 课 原文&#xff1a;medium.com/hiromi_suenaga/deep-learning-2-part-2-lesson-12-215dfbf04a94 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 来自 fast.ai 课程的个人笔记。随着我继续复习课程以“真正”理解它&#xff0c;…

Java 基于微信小程序的私家车位共享系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

LC 987. 二叉树的垂序遍历

987. 二叉树的垂序遍历 难度 : 困难 题目大意&#xff1a; 给你二叉树的根结点 root &#xff0c;请你设计算法计算二叉树的 垂序遍历 序列。 对位于 (row, col) 的每个结点而言&#xff0c;其左右子结点分别位于 (row 1, col - 1) 和 (row 1, col 1) 。树的根结点位于 …

爬虫2—用爬虫爬取壁纸(想爬多少张爬多少张)

先看效果图&#xff1a; 我这个是爬了三页的壁纸60张。 上代码了。 import requests import re import os from bs4 import BeautifulSoupcount0 img_path "./壁纸图片/"#指定保存地址 if not os.path.exists(img_path):os.mkdir(img_path) headers{ "User-Ag…

【STL】string的模拟实现

string类的模拟实现 一、接口函数总览二、默认成员函数1、构造函数2、拷贝构造函数&#xff08;1&#xff09;写法一&#xff1a;传统写法&#xff08;2&#xff09;写法二&#xff1a;现代写法 3、赋值运算符重载函数&#xff08;1&#xff09;写法一&#xff1a;传统写法&…