• ElasticSearch深浅分页查询及原理


    一、from-size(深分页)

    1、分页原理

    假设有8分片,查询到第1000页数据,from =1000 size=100,es每次会从取出每个分片取1000*100+100=11w条数据,自然每个分片都会存储这11w条数据,然后再发给协调节点做排序后,而协调节点就是面临处理8*11w=88w条的巨大压力

    随着from页码的不断增加,es从每个分片获取的数据量也就越来越大,自然越来越慢,于es所在服务器和应用系统都带来不小压力,甚至出现内存溢出风险。因此es默认使用10000作为最大查询值,超过此值,推荐使用scroll游标来滚动查询。

    2、踩坑指南

    如果初次使用,不注意的话,当超过10000时候,查询会报如下异常,

    Result window is too large, from + size must be less than or equal to: [10000] but was [22020]. 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

    当然10000也可以调整,,如最大上限调整为800000

    PUT my_index/_settings
    {"index.max_result_window":"800000"}

    二、滚动查询(浅分页)

    1、基本原理

    总体而言,scroll查询顾名思义-滚动查询,类似于关系型数据库oracle的cursor游标。初次查询时,将所有符合搜索条件的doc _id集排序后存储在上下文,类似于快照。在之后每次遍历时,带着上次的_scroll_id从这个快照里取size数据,从而从各自_scroll_id对应的分片获取数据。

    那么有人说假设一次搜索满足条件的有1000w个doc _id,甚至更多的时候,会不会撑爆内存。这个不用担心,es使用了非常紧凑的数据结构和压缩算法来存放这些ID,占用的内存不会太多。


    详细的说,初次查询大致分为两个阶段

    Query阶段:将每个shard将命中的结果( doc_id和_score) 按照 _score 顺序在上下文中创建一个优先队列快照,并通过scroll_id指向它,lastEmittedDoc指向上次访问的位置,最后将TOP(size)的doc id返回给协调节点。

    Fetch阶段:协调节点将各个shard返回的结果再进行合并排序,最后通过doc_id查找返回结果的全量数据。之后更新各个分片上的上下文。

    初次之后查找数据,在Query阶段通过scroll_id找到对应的快照,然后用lastEmittedDoc将原来的查询语句添加bool查询条件**( >=lastEmitted.doc + 1)**,在快照中找数据。

    scroll_id也不是固定的,scroll_id其中保留了shard信息,假如scroll查询语句需要路由到16个shard上查。scroll_id会比较长,记录这16个shard。有可能从开始到完成都需要路由到这16个shard,shard_id就不会变化。也有可能随着不断进行scroll,需要路由到的shard越来越少,shard_id也会越来越短,随之变化。

    2、操作步骤

    (1)初始化scroll缓存

    初次请求,要在url中的search后加上scroll=2m,这个scroll=2m(2m代表2分钟),是缓存时间,客户端可以根据查询数据数量自定义缓存的时间

    1. POST my_index/_search?scroll=2m
    2. {
    3.   "from": 0,
    4.   "size": 150,
    5.   "query": {
    6.     "bool": {
    7.       "must": [
    8.         {
    9.           "term": {
    10.             "bill_month": {
    11.               "value": "2022-06",
    12.               "boost": 1
    13.             }
    14.           }
    15.         }
    16.       ]
    17.     }
    18.   }
    19. }

    返回如下,会发现比不带scroll=2m,多返回了一个_scroll_id值为base64的字符串编码

     (2)使用_scroll_id继续请求

    用每次得到的这个_scroll_id值,继续请求下一页(这个为了偏于展示,这里_scroll_id值写短些),每次请求最好都带上scroll=2m刷新过期时间,以防超时报错。

    1. POST my_index/_search?scroll=2m
    2. {
    3.     "scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAMQhbFkhrUXE3eE0tUy1LMkxRMDlhOGU1dEEA"
    4. }
    超时会抛出如下异常
     Elasticsearch exception [type=search_context_missing_exception, reason=No search context found for id [3344636]
    

    (3)清除scroll

    这个_scroll_id在es的服务端是有缓存数量限制的,默认最大500,如果请求量大于这个值,会报错。因此除了自然过期之外,我们在处理完成本次请求后一般手动清除掉_scroll_id缓存,及早释放资源

    1. DELETE /_search/scroll
    2. {
    3. "scroll_id": "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAQ7QAFmtZT3luT3M0UUVDdE82MFp4QmtNcGcAAAAAADOE-hYyMDBxb29mb1J0bWdrS2ZwQ2FhSFZ3AAAAAAAxFi4WSGtRcTd4TS1TLUsyTFEwOWE4ZTV0QQ=="
    4. }

    参考:取回阶段 | Elasticsearch: 权威指南 | Elastic

    参考:elasticsearch scroll查询的原理没太懂 - Elastic 中文社区

    参考:es分页查询原理_喂喂喂_java的博客-CSDN博客_es 分页查询

  • 相关阅读:
    算法——哈希表篇
    [机缘参悟-27]:鬼谷子-反应篇-反说之术,以毒攻毒,以错推错
    2022年Java面试题
    财务指标初步学习笔记
    [剑指 Offer 06]从尾到头打印链表
    读取PDF中指定数据写入EXCEL文件
    C语言中 -> 和 . 的区别
    [附源码]java毕业设计毕业生离校管理系统
    linux文件权限与目录配置
    CleanMyMac X2023标准版解锁完整版本Mac电脑清理专家
  • 原文地址:https://blog.csdn.net/lzxlfly/article/details/125466213