https://github.com/memoryFuhao/elasticsearch_client (打个广告 以上链接是本人开发的一个es客户端工具,支持es大部分 CRUD操作 分页、分组、嵌套分组、and or ···,有需要的朋友可以pull代码直接使用)
今天收到测试提到的一个关于Elasticsearch分页查询的bug(当Elasticsearch查询到50万页(每页显示20条数据)的时候,es会卡顿很长时间也查不出数据),之前一直没去研究过Elasticsearch的分页查询,正好趁着这个机会可以研究一下,以下内容是本人对Elasticsearch分页的理解:
Elasticsearch分页查询的两种实现方式:
a)使用from、size完成(普通分页)。
官方文档说明:https://www.elastic.co/guide/en/elasticsearch/reference/6.3/search-request-from-size.html
#从0开始查询10条数据,相当于pageNum=1 pageSize=10
curl -X GET "localhost:9200/test/_search" -H 'Content-Type: application/json' -d'
{
"from" : 0, "size" : 10,
"query" : {
"term" : { "user" : "kimchy" }
}
}
'
这种方式实现原理其实是很暴力的,直接查询出一批数据,然后根据分页参数计算保留符合数据返回客户端,其他数据直接丢弃。
默认只能支持10000以内的分页查询,当然用户也可以通过调整索引settings参数将10000这个参数调大,参数为index.max_result_window。
但是并不建议通过修改参数的方式来完成分页查询,因为将参数调的太大很可能会出现OOM异常。
b)使用Scroll完成(深度分页):
官方文档说明:https://www.elastic.co/guide/en/elasticsearch/reference/6.3/search-request-scroll.html
#查询100条数据,scroll=1m表示在服务器端将结果数据保留1分钟(这个参数是完成深度分页的重要参数)
curl -X POST "localhost:9200/objext_result/_search?scroll=1m" -H 'Content-Type: application/json' -d'
{
"size": 100,
"query": {
"match" : {
"bag" : 0
}
}
}
'
#根据第一步查询返回的_scroll_id 继续往下进行分页(每次执行一次会替换结果数据,但是_scroll_id不会改变),query查询与第一步中内容是一致的。
curl -X POST "localhost:9200/_search/scroll" -H 'Content-Type: application/json' -d'
{
"scroll" : "1m",
"scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAXJDFnkwRTJ1YW1yUU1xWWN4ZFJBM1FrTVEAAAAAAAFyRRZ5MEUydWFtclFNcVljeGRSQTNRa01RAAAAAAABckQWeTBFMnVhbXJRTXFZY3hkUkEzUWtNUQAAAAAAAXJCFnkwRTJ1YW1yUU1xWWN4ZFJBM1FrTVEAAAAAAAFyQhZoWVNaRmNyTFNDeVBiODRSWUswb01B"
}
'
这种方式的实现原理和数据库中的游标类似,简单的来说就是第一次查询一批数据并将数据保存起来,如果没有所需数据就继续查询,直到查询到
分页对应数据为止。该方式就不会出现a)中的OOM异常,因为每次查询的都是固定size的数据(后面查询的结果数据会覆盖前面查询的结果数据),理论上来说可以遍历全部数据。
Elasticsearch分页查询两种方式存在问题:
a)普通分页存在问题:
1.在海量数据情况下,不能进行深度分页,默认只能查询前10000条数据。
2.如果想用此方式做深度分页,会造成资源浪费,资源不足时会出现OOM异常。
b)深度分页存在问题:
1.虽然理论上能够查询到最后一页数据,但是Scroll的机制决定了页数越大,查询返回速度会越慢。
2.不能在服务器端进行跳页查询。
Elasticsearch分页总结:
其实Elasticsearch提供的这两种分页查询的方式已经可以满足绝大部分业务需求了。
一般这种海量查询的场景用户只会关心前面页数的数据。
PS: 假如用户有查询尾页的需求怎么办? 一般这种查询的时候都会进行排序,我们可以在用户点尾页的时候将排序方式替换(比如从asc转为desc),以达到跳尾页快速响应的要求。