Elasticsearch分页解决方案

Elasticsearch分页解决方案

一、命令的方式做分页

1、常见的分页方式:from+size

elasticsearch默认采用的分页方式是from+size的形式,但是在深度分页的情况下,这种使用方式的效率是非常低的,比如from=5000,size=10,es需要在各个分片上匹配排序并得到5000*10条有效数据,然后在结果集中取最后10条数据返回。除了会遇到效率上的问题,还有一个无法解决的问题是es目前支持最大的skip值是max_result_window默认为10000,也就是说当from+size > max_result_window时,es将返回错误。

解决方案:

        问题描述:比如当客户线上的es数据出现问题,当分页到几百页的时候,es无法返回数据,此时为了恢复正常使用,我们可以采用紧急规避的方式,就是将max_result_window的值调至50000。

 

curl -XPUT "127.0.0.1:9200/custm/_settings" -d 
'{ 
    "index" : { 
        "max_result_window" : 50000 
    }
}'

对于上面这种解决方案只是暂时解决问题,当es的使用越来越多时,数据量越来越大,深度分页的场景越来越复杂时,可以使用另一种分页方式scroll。

 

在分布式系统中深度分页

理解为什么深度分页是有问题的,我们可以假设在一个有 5 个主分片的索引中搜索。 当我们请求结果的第一页(结果从 1 到 10 ),每一个分片产生前 10 的结果,并且返回给 协调节点 ,协调节点对 50 个结果排序得到全部结果的前 10 个。

现在假设我们请求第 1000 页—​结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不产生前10010个结果以外。 然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果中的 50040 个结果。

可以看到,在分布式系统中,对结果排序的成本随分页的深度成指数上升。这就是 web 搜索引擎对任何查询都不要返回超过 1000 个结果的原因。

 

2、scroll方式

为了满足深度分页的场景,es提供了scroll的方式进行分页读取。原理上是对某次查询生成一个游标scroll_id,后续的查询只需要根据这个游标去取数据,知道结果集中返回的hits字段为空,就表示遍历结束。Scroll的作用不是用于实时查询数据,因为它会对es做多次请求,不肯能做到实时查询。它的主要作用是用来查询大量数据或全部数据。

使用scroll,每次只能获取一页的内容,然后会返回一个scroll_id。根据返回的这个scroll_id可以不断地获取下一页的内容,所以scroll并不适用于有跳页的情景

使用curl进行深度分页读取过程如下:

1、 先获取第一个scroll_id,url参数包括/index/type和scroll,scroll字段指定了scroll_id的有效生存时间,过期后会被es自动清理。

[root@master ~]# curl -H "Content-Type: application/json" -XGET '192.168.200.100:9200/chuyun/_search?pretty&scroll=2m' -d'
{"query":{"match_all":{}}, "sort": ["_doc"]}'

2、在遍历时候,拿到上一次遍历中的_scroll_id,然后带scroll参数,重复上一次的遍历步骤,直到返回的数据为空,表示遍历完成。
每次都要传参数scroll,刷新搜索结果的缓存时间,另外不需要指定index和type(不要把缓存的时时间设置太长,占用内存)后续查询:

curl -H "Content-Type: application/json" -XGET '192.168.200.100:9200/_search/scroll?pretty'  -d'
{
    "scroll" : "2m", 
    "scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAABWFm43cDd3eERJVHNHMHJzSlNkajdPUHcAAAAAAAAAVxZuN3A3d3hESVRzRzByc0pTZGo3T1B3AAAAAAAAAFsWazlvUFptQnNTdXlmNmZRTl80cVdCdwAAAAAAAABVFm43cDd3eERJVHNHMHJzSlNkajdPUHcAAAAAAAAAWhZrOW9QWm1Cc1N1eWY2ZlFOXzRxV0J3" 
}'

 

 

3、scroll的删除

删除所有scroll_id

curl -XDELETE 192.168.200.100:9200/_search/scroll/_all
 

指定scroll_id删除:

curl -XDELETE 192.168.200.100:9200/_search/scroll -d 
'{"scroll_id" : ["cXVlcnlBbmRGZXRjaDsxOzg3OTA4NDpTQzRmWWkwQ1Q1bUlwMjc0WmdIX2ZnOzA7"]}'

3、 search_after 的方式

使用search_after必须要设置from=0。

这里我使用_id作为唯一值排序。

我们在返回的最后一条数据里拿到sort属性的值传入到search_after。

scroll的方式,官方不建议用于实时的请求(一般用于数据导出),因为每一个scroll_id不仅会占用大量的资源,而且会生成历史快照,对于数据的变更不会反映到快照上。而search_after分页的方式是根据上一页的最后一条数据来确定下一页的位置,同时再分页请求的过程中,如果有索引数据的增删改查,这些变更也会实时的反映到游标上。但是需要注意,因为每一页的数据依赖于上一页的最后一条数据,所以没法跳页请求。

为了找到每一页最后一条数据,每个文档那个必须有一个全局唯一值,官方推荐使用_uuid作为全局唯一值,当然在业务上的id也可以。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ch3nnn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值