title: ElasticSearch之深度应用及原理剖析
author: Xoni
tags:

  • 搜索引擎
  • Elasticsearch
    categories:
  • 搜索引擎
  • Elasticsearch
    abbrlink: 5a1f6e0b

第14节 deep paging性能问题 和 解决方案

es 分页查询 demo java es分页查询原理_java

深度分页问题

ES 默认采用的分页方式是 from+ size 的形式,类似于mysql的分页limit。当请求数据量比较大时, Elasticsearch会对分页做出限制,因为此时性能消耗会很大。举个例子,一个索引 分10个 shards,然后,一个搜索请求,from=990,size=10,这时候,会带来严重的性能问题:

  • CPU
  • 内存
  • IO
  • 网络带宽

es 分页查询 demo java es分页查询原理_面试_02

CPU、内存和IO消耗容易理解,网络带宽问题稍难理解一点。在 query 阶段,每个shard需要返回 1000条数据给 coordinating node,而 coordinating node 需要接收 10*1000 条数据,即使每条数据只有 _doc _id 和 _score,这数据量也很大了,而且,这才一个查询请求,那如果再乘以100呢?
es中有个设置 index.max_result_window,默认是10000条数据,如果分页的数据超过第1万条,就拒绝返回结果了。如果你觉得自己的集群还算可以,可以适当的放大这个参数,比如100万。
我们意识到,有时这种深度分页的请求并不合理,因为我们是很少人为的看很后面的请求的,在很多的业务场景中,都直接限制分页,比如只能看前100页。
不过,这种深度分页确实存在,比如有1千万粉丝的微信大V,要给所有粉丝群发消息,或者给某省粉丝群发,这时候就需要取得所有符合条件的粉丝,而最容易想到的就是利用 from + size 来实现,但这是不现实的,我们需要使用下面的解决方案。

深度分页解决方案

利用 scroll 遍历方式

**

  • 初始化时将所有符合搜索条件的搜索结果缓存起来,可以想象成快照
  • 在遍历时,从这个快照里取数据,也就是说,在初始化后对索引插入、删除、更新数据都不会影响遍历结果。

因此,scroll 并不适合用来做实时搜索,而更适用于后台批处理任务,比如群发。

1)初始化

POST /book/_search?scroll=1m&size=2 
{
	"query": {
	  "match_all": {}
	}
}

初始化时需要像普通 search 一样,指明 index 和 type (当然,search 是可以不指明 index 和 type 的),然后,加上参数 scroll,表示暂存搜索结果的时间,其它就像一个普通的search请求一样。
初始化返回一个 scroll_id,scroll_id 用来下次取数据用

  1. 遍历
GET /_search/scroll
{ 
  "scroll": "1m",
  "scroll_id" : "步骤1中查询出来的值"
}

这里的 scroll_id 即 上一次遍历取回的 _scroll_id 或者是初始化返回的 _scroll_id,同样的,需要带scroll 参数。 重复这一步骤,直到返回的数据为空,即遍历完成。注意,每次都要传参数 scroll,刷新搜索结果的缓存时间。另外,不需要指定 index 和 type。设置scroll的时候,需要使搜索结果缓存到下一次遍历完成,同时,也不能太长,毕竟空间有限。

search after方式

满足实时获取下一页的文档信息,search_after 分页的方式是根据上一页的最后一条数据来确定下一页的位置,同时在分页请求的过程中,如果有索引数据的增删改,这些变更也会实时的反映到游标上,这种方式是在es-5.X之后才提供的。为了找到每一页最后一条数据,每个文档的排序字段必须有一个全局唯一值 使用 _id 就可以了。

GET /book/_search
{
  "query": {
    "match_all": {}
  },
  "size": 2,
  "sort": [
    {
      "_id": "desc"
    }
  ]
}

GET /book/_search
{
  "query": {
    "match_all": {}
  },
  "size": 2,
  "search_after": [
    3
  ],
  "sort": [
    {
      "_id": "desc"
    }
  ]
}

下一页的数据依赖上一页的最后一条的信息所以不能跳页。

三种分页方式比较

es 分页查询 demo java es分页查询原理_elasticsearch_03