使用es的from/size进行常规的分页操作时,有一个max_window_size限制,大小默认是10000,当from+size > 10000时,会有如下报错:
"error": {
"root_cause": [
{
"type": "query_phase_execution_exception",
"reason": "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 setting."
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "uat_defect_info",
"node": "nqwAvcL9QMqLKIo67GrI8A",
"reason": {
"type": "query_phase_execution_exception",
"reason": "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 setting."
}
}
]
},
"status": 500
}
解决方法在错误提示中也已经说了:from+size必须小于10000,你可以使用scroll api去获取更多的数据或者修改index.max_result_window。
在这里有必要了解一下from/size的原理,因为es是基于分片的,加入有5个分片,from+size=100,size=10,则会根据排序规则从5个分片中取回from+size(100)条数据数据,然后汇总也就是500条数据,然后从这500条中选择最后面的10条数据。
加入是10000条的话,则就变成50000条了,或者分片数量更多呢?
页面越大或者分页越深,需要排序的量也就越大,效率就会越低。
注:这里并不是大家想的,每个分片取十条数据,然后汇总成五十条然后最后从50条中返回十条。
scroll 类似于sql中的cursor,使用scroll,每次只能获取一页的内容,然后会返回一个scrollid,根据scrollid可以不断地获取下一页的内容,所以scroll并不适用于有跳页的情景。
但是在真正的使用场景中,第10000条数据已经是很后面的数据了,可以“折衷”一下,不提供跳转页面功能,只能下一页的翻页,因为在实际的应用中,不会有人特别无聊的一直翻页,翻到1W页以后。
滚动上下文是昂贵的,并不建议将其用于实时用户请求。
建议使用scroll来获取es中的全量数据。
eg: 使用scroll请求,并设置scrollid只保留1分钟。
POST /twitter/_search?scroll=1m
{
"size": 100,
"query": {
"match" : {
"title" : "elasticsearch"
}
}
}
使用scroll之后会返回一个scrollid,用scrollId可以不断地请求到下一页的数据:
POST /_search/scroll
{
"scroll" : "1m",
"scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ=="
}
使用完scroll之后,记得手动删除scroll:
DELETE /_search/scroll
{
"scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ=="
}
详情可转:scroll API
search after和scroll类似,都是通过当前状态迭代,但是search after更加依赖排序。
每个文档具有一个唯一值的字段应用作排序规范的仲裁。 否则,具有相同排序值的文档的排序顺序将是未定义的。 建议的方法是使用字段 _uid,它确保每个文档包含一个唯一值。
GET twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "elasticsearch"
}
},
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}
然后根据返回的sort域的值,作为下一个请求after search 的参数。
GET twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "elasticsearch"
}
},
"search_after": [1463538857, "654323"],
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}
在这里,search_after参数作用类似于scroll id,使用search after 要求sort是稳定的,不常变更,同样,适用于的上一页/下一页的切换,并不适用于页数直接跳转。
详情参见:Search After API