Elasticsearch:Scroll深度分页与返回全部数据
在使用ES时,有时候不可避免的要返回大量的数据或者说返回满足你的查询条件的全部数据,而满足你的条件的数据可能只是上百条也可能是上万条。当需要返回的数据量特别大时怎么办呢?
方法一 设置size
在使用aggregations情况下,聚合的结果和直接查询一样默认都会只返回十条。如果超过10条就需要通过size來设置,但是如何让他返回全部的数据呢?在网上有人说聚合时设置size为0来返回全部数据,经测试不可行(用的是5.6版本的),不使用聚合时的size可以设为0或-1,但是聚合内的size必须要大于0。
除此之外也可以改变size的最大值,size的默认值最大值为10000,但是可以通过如下语句来设置size的最大值:
curl -XPUT http://127.0.0.1:9200/index/_settings -d '{ "index" : { "max_result_window" : 1000000}}'
方法二 from and size分页
使用 from and size 进行分页。但是es官方并不建议用这种方法进行大数据的查询尤其是深度分页,具体原因我们要知道它是如何查询的。
size为返回的结果个数,默认为10;from表示从第几行开始,不包含在内。
假设我们在有5个主分片的索引中搜索,查询第一页数据,即前10条数据,那么es会从每个分片中生成排序好的结果,取出前10条,然后返回给请求节点,请求节点再将这50条记录再次排序选出前10条。
但是如果请求的是第1000页的数据,即第10001至第10010条数据。那么es会从5个分片中取出各个分片顶端的10010条数据,然后将这总共50050条数据返回给请求节点,请求节点再次对这50050条数据进行一次全局排序,取出第50041至50050条数据,抛弃50040条数据,这就造成了很大的浪费。
在分布式系统中排序的花费会随着分页的深度而成倍增长,如果数据特别大对CPU和内存的消耗会非常巨大甚至会导致OutOfMemory,所以这也是为什么网络搜索引擎不能返回多余1000个结果的原因
方法三 scroll and scan滚屏。
scroll的作用不是用于实时查询数据,因为他会对es做多次请求,不可能做到实时查询。它的作用主要是用来查询大量数据或全部数据。
初始查询:
curl -XGET 'localhost:9200/index/type/_search?scroll=1m' -d '
{
"query": {
"match" : {
"title" : "elasticsearch"
}
}
}
后续查询:
curl -XGET 'localhost:9200/_search/scroll' -d'
{
"scroll" : "1m",
"scroll_id" : "c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1"
}
注意:
1,scroll设置的一分钟,会随着每次的滚屏而刷新。此处不是指整个查询限时为1分钟,而是到下一次滚屏还有1分钟的时间。
2,后续请求时url中不应该有index和type,这些都在初始请求中,只需要使用scroll_id和scroll两个参数即可,其中scroll_id可以放在url中也可以放在请求体中
第一次请求时es会生成一个初始查询时索引的快照,并将旧的数据保护在手边,所以第一次查询之后对文档的一些改动不会影响查询结果。后续的每次请求都会记住哪些结果已经返回了,下一次继续返回剩下的,直到hits里的数据为空。但是scroll按照默认的进行排序依旧会是有消耗的,所以我们继续引入scan查询。
深度分页代价最高的就是全局排序,使用scan只需要把search_type设置成scan就可以禁用全局排序,如下:
GET /old_index/_search?search_type=scan&scroll=1m
{
"query": { "match_all": {}},
"size": 1000
}
GET /_search/scroll?scroll=1m
c2Nhbjs1OzExODpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzExOTpRNV9aY1VyUVM4U0 <2>
NMd2pjWlJ3YWlBOzExNjpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzExNzpRNV9aY1Vy
UVM4U0NMd2pjWlJ3YWlBOzEyMDpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzE7dG90YW
xfaGl0czoxOw==
扫描式滚屏和标准滚屏的区别有以下几点:
1,scan结果没有排序,返回结果是doc在es中的顺序。
2,scan初始查询的结果中hits中不会有数据
3,因为没有排序,所以也不会支持聚合的一些操作
4,scan中size被应用到每一个分片上,所以我们在每次滚屏是最多获得size * number_of_primary_shards(size*主分片数) 个document
另外还有search after也可以一些聚合后的操作
参考资料《Elasticsearch权威指南》