es分页和mysql分页_es深度分页查询

前言

近期在做新的项目时,使用了ElasticSearch作为数据的存储和查询。接到了一个比较恶心的需求,需要对es进行分页查询,单次查询一万条,最多需要查询十次。当时也没想太多,需求评审时并没有及时反驳,既然掉坑里了,那就想办法爬出来吧!

es的分页

1)from+size浅分页

我们当时有点想当然了,以为from+size就可以搞定(业务代码写多的后果)。实际测试的时候,发现内存消耗特别大,而且速度也很一般。ES的查询机制如下:

es分页和mysql分页_es深度分页查询_第1张图片

假设我们的ES有三个节点,当分页查询请求过来时,如果落到node1节点,那么node1节点将会向node2和node3发送同样的查询请求,每个节点将topN的文档返回(这里只返回文档的id以及打分排序的字段,减少数据传输),node1会对三个节点的所有文档(3*N个)进行排序,取topN后再根据文档的id到对应的节点上查询整个文档数据,最后返回客户端。

而对于分页查询,比如from=10000,szie=10000,其实每个节点需要查询from+size=20000条数据,排序之后截取后10000条数据。当我们进行深度分页,比如查询第十页数据时,每个节点需要查询10*size=10W条数据,这个太恐怖了。而且默认情况下,当from+size大于10000时,查询会抛出一个异常,ES2.0后有一个max_result_window属性的设置,默认值是10000,也就是from+size的最大限度。当然你可以修改这个值作为临时的应对策略,不过治标不治本,产品也只会变本加厉!

2)scroll查询

ES支持scroll滚屏查询,有兴趣的同学可以了解一下,网上相关的文档不少。不过根据ES官网的描述,scroll查询是很耗性能的方式,不建议在实时查询中运用。摘抄自官网:The Scroll api is recommended for efficient deep scrolling but scroll contexts are costly and it is not recommended to use it for real time user requests.

3)search_after查询

search_after是ES5.0及之后版本提供的新特性,search_after有点类似scroll,但是和scroll又不一样,它提供一个活动的游标,通过上一次查询最后一条数据来进行下一次查询。

比如第一次查询如下:

GET zm/recall/_search

{"query": {"match_all": {}

},"sort": [

{"lastModifyTime": {"order": "desc"}

}

],"size": 10}

这里根据更新时间进行排序,拿到的结果如下:

{"_index": "zmrecall","_type": "recall","_id": "60310505115909","_score": null,"_source": {"userId": 60310505115909,"score": 1,"city": [276],"sex": 1,"age": 29,"lastModifyTime": 1545037514},"sort": [1545037514]

}

注意到返回结果中有一个sort字段,所以下一次查询的时候,只需要将本次查询最后一条数据中的排序字段加入查询即可:

GET zm/recall/_search

{"query": {"match_all": {}

},"sort": [

{"lastModifyTime": {"order": "desc"}

}

],"search_after": [1545037514],//这个值与上次查询最后一条数据的sort值一致,支持多个"size": 10}

这里需要说明一下,使用search_after查询需要将from设置为0或-1,当然你也可以不写

另外在ES6.5的文档中有这样一句话需要注意一下:

es分页和mysql分页_es深度分页查询_第2张图片

大致的意思就是,如果search_after中的关键字为654,那么654323的文档也会被搜索到,所以在选择search_after的排序字段时需要谨慎,可以使用比如文档的id或者时间戳等

另外,search_after并不是随机的查询某一页数据,而是并行的滚屏查询;search_after的查询顺序会在更新和删除时发生变化,也就是说支持实时的数据查询

081a54fb3771e9a2480aaf822addd100.png

总结

在使用一个工具之前,一定要对其内部的基本流程有一个简单的了解,否则出现问题时不知从何入手。search_after相比较上面的浅分页以及scroll滚屏查询会有很大的性能提升,推荐大家使用!

最后附上ES的官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/6.5/search-request-search-after.html

另外在csdn上也看到一个博客,讲的很不错:https://blog.csdn.net/ctwy291314/article/details/82754652

你可能感兴趣的:(es分页和mysql分页)