elasticsearch分页对于用过es的人应该都会使用 ,和数据库的分页类似,如下所示,通过from + size可以对数据进行分页。
{
"from" : 0,
"size" : 10,
"query" : {
"term" : { "user" : "dejun" }
}
}
可以查询1-10条记录,不过由于es是分布式的,数据都是分布在多个分片上。
如查询: from = 990 , size = 10 , 分片数为:4 ,那么es是如何 查询的呢? 如下图所示:
es会在每个分片获取1000条文档,通过Coordinating Node 汇总各个节点的数据,再通过排序选择前1000个文档返回。
所以当页数越深,查询的节点的数量越大,自然占用的内存也越多,那么我们是不是可以把系统内存查爆? ES为了避免深度分页带来的内存开销,ES默认限定只能查询10000个文档
那么我们做个示范:
POST /demo/_search
{
"from" : 0 ,
"size" : 10001 ,
"query" : {
"match_all":{}
}
}
ES会报以下错误:
Result window is too large, from + size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level parameter.
以上可见,from + size 这种方式不适用于深度分页场景,下面介绍其它两种分页方式…
- Search After
- Scroll Api
Search After
可以避免深度分页带来的性能问题,可以实时的获取下一页文档
不支持指定页数,只能向下翻
需要加入排序 sort,并且排序的字段一定要是唯一的
示例:
POST /demo/_search
{
"size": 3,
"query": {
"terms": {
"txAcctNo": ["11111"
]
}
},
"sort" :{
"_id" :"desc"
}
}
ES返回:
{
"took": 110,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1122,
"max_score": null,
"hits": [
{
"_id": "6140202001021427303890174574324",
"_score": null,
"_source": {
},
"sort": [
"6140202001021427303890174574324"
]
},
{
"_id": "6140201912131352403980169574091",
"_score": null,
"_source": {
},
"sort": [
"6140201912131352403980169574091"
]
},
{
"_id": "6140201912101038085680169566509",
"_score": null,
"_source": {
},
"sort": [
"6140201912101038085680169566509"
]
}
]
}
}
每条数据都会有一个sort返回,只需要在下一次查询中,在search_after中加入这个值,如下:
POST /demo/_search
{
"size": 3,
"query": {
"terms": {
"txAcctNo": ["11111"
]
}
},
"sort" :{
"_id" :"desc"
},
"search_after" :[
"6140202001171118484170182578541"
]
}
以上即是search_after的用法,其实很简单,那么为什么search_afterr适合深度分页呢,来看一下原理:
假设size:10 ,查询10000-10010,search_after会通过唯一排序的值定位,每个节点只会查10条数据,避免了内存开销过大的问题