es 深度分页问题

es 深度分页问题

背景

使用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

在这里有必要了解一下from/size的原理,因为es是基于分片的,加入有5个分片,from+size=100,size=10,则会根据排序规则从5个分片中取回from+size(100)条数据数据,然后汇总也就是500条数据,然后从这500条中选择最后面的10条数据。
加入是10000条的话,则就变成50000条了,或者分片数量更多呢?
页面越大或者分页越深,需要排序的量也就越大,效率就会越低。
注:这里并不是大家想的,每个分片取十条数据,然后汇总成五十条然后最后从50条中返回十条。

scroll

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

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

你可能感兴趣的:(elasticsearch,分页)