Fork me on GitHub

ES分页查询速度慢调优

es分页查询

方式一:from + size

from + size方式查询
from表示页码
size表示页面大小
比如from为30,size为100,则要查询第30页,展示100条数据
那么es查询的方式为获取到查询条件(略)下的30 * 100等于3000条数据,然后给你返回最后的100条数据,前面的2900条数据将被过滤掉

而且es是有多个分片的话,将从每个分片去取得相应条件下的数据,然后汇总为3000条,最后返回其中的100条,所以分页越深,ES处理的开销就越大,占用内存就越大。
优点
方式简单,容易上手,针对数据量小的浅分页,速度可以满足要求
缺点
深分页时查询速度慢,对服务器内存开销大

方式二:scroll方案

通过scroll方式可以一次性查询大量的数据,甚至全量数据,我们的第一次查询(会返回一个scroll_id,使用此scroll_id来查询下一组size大小的数据),会生成一个当前查询条件的快照,后面的每次(翻页)滚屏都是基于这个快照的结果,即使有新的数据进来,也不会影响这个快照的结果.
第一次查询如下:
POST /kibana_sample_data_ecommerce/_search?scroll=1m
{
    "size": 10,
    "query": {
        "match_all" : {
        }
    }
}
scroll=1m表示很多人对scroll这个参数容易混淆,误认为是查询的限制时间。这个理解是错误的。这个时间其实指的是es把本次快照的结果缓存起来的有效时间。
scroll 参数相当于告诉了ES我们的search context要保持多久,后面每个 scroll 请求都会设置一个新的过期时间,以确保我们可以一直进行下一页操作。

通过scroll_id去拿数据的时候,可以不用设置index(索引名)跟size(数据大小)信息,类似如下:
POST /_search/scroll
{
    "scroll" : "1m",
  "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAA5AWNGpKbFNMZnVSc3loXzQwb0tJZHBtZw=="
}
以此类推,后面每次滚屏都把前一个的scroll_id复制过来

为什么scroll比较块

ES的检索分为query(查询)和fetch(获取)阶段,query阶段的效率比较高,只是将满足条件的文档id汇总起来,fetch阶段基于每个分片的结果在coordinating(坐标)节点上进行全局排序,然后最终计算出结果。

scroll查询的时候,在query阶段把符合条件的文档id保存在 search context(搜索上下文)中,后面每次scroll分批取出只是根据scroll_id定位到游标的位置,然后抓取size大小的结果集即可。 
优点
适合实时性要求不高,要查询大量数据的场景,适合报表导出等业务或者ES内部的重置索引
缺点
实时性不高,只是往下一页迭代查询,不能往回查询且不能获取跳页查询

方式三:search after方案

search after使用实时游标来帮我们解决实时滚动的问题,简单来说前一次查询的结果会返回一个唯一的字符串,下次查询再带上这个字符串
第一次查询:
GET /kibana_sample_data_ecommerce/_search
{
  "size" : 2,
  "query": {
    "bool": {
      "must": [
        {"match": {
          "customer_first_name": "Diane"
        }}
      ],
      "filter": {
        "range": {
          "order_date": {
            "gte": "2020-01-03"
          }
        }
      }
    }
  }, 
  "sort": [
    {
      "order_date": "desc",
      "_id": "asc"
      
    }
  ]
}

数据返回结果的最后一条里面能获取到order_date与_id
于是我们将使用search after
GET /kibana_sample_data_ecommerce/_search
{
  "size" : 2,
  "query": {
    "bool": {
      "must": [
        {"match": {
          "customer_first_name": "Diane"
        }}
      ],
      "filter": {
        "range": {
          "order_date": {
            "gte": "2020-01-03"
          }
        }
      }
    }
  }, 
  "search_after": 
      [
          1580597280000,
          "RZz1f28BdseAsPClqbyw"
        ],
  "sort": [
    {
      "order_date": "desc",
      "_id": "asc"
      
    }
  ]
}
 "search_after":[1580597280000,"RZz1f28BdseAsPClqbyw"] 说明: search_after数组里面是多个排序参数,用逗号隔开
当使用search_after参数时,from的值必须被设为0或者-1

实现原理

因为我们search_after传递了排序的唯一标识,ES只需从每个分片上拿到满足条件的文档数量就行了,然后基于这些文档最终聚合成10条结果返回
优点
基于ES内部排序好的游标,可以实时高效的进行分页查询
缺点
只能做下一页这样的查询场景,不能随机的指定页数查询(跳页)。
posted @ 2022-05-23 15:06  三脚半猫  阅读(3503)  评论(0编辑  收藏  举报