Elasticsearch 7.x如何设置精确分页大小?对比2.4版本差异
嘿,这个问题我刚好有经验,来给你梳理清楚~其实Elasticsearch 7.x里并不是完全不能用from+size实现精确分页,只是要分场景来看,同时还要注意深度分页的限制:
一、基础分页场景(数据量较小)
如果你的分页深度没有超过Elasticsearch默认的index.max_result_window值(默认是10000),直接用from和size依然能得到精确数量的结果。
这里要纠正一个误解:7.x里说size是“最大数量”,是指当符合条件的文档总数不足size时,会返回实际存在的文档数;但如果符合条件的文档足够多,只要from的位置正确,就会返回正好size条数据,和2.4版本的效果一致。
举个例子,要获取第11-20条数据,请求如下:
GET /your_index/_search { "from": 10, "size": 10, "query": { // 你的查询条件 "match_all": {} }, "sort": [ // 确保排序字段稳定,避免分页重复/遗漏 {"create_time": "desc", "_id": "asc"} ] }
二、深度分页场景(数据量超过10000)
当分页深度超过index.max_result_window时,直接用from+size会报错,这时候需要用更高效的方式实现精确分页,推荐用search_after,其次是scroll。
1. 推荐方案:search_after
search_after是Elasticsearch官方推荐的深度分页方案,它基于上一页最后一条文档的排序字段值来定位下一页,避免了from+size的性能问题,也没有结果窗口的限制。
步骤如下:
第一次查询:获取第一页数据,同时记录最后一条文档的排序字段值
GET /your_index/_search { "size": 10, "query": { "match_all": {} }, "sort": [ {"create_time": "desc", "_id": "asc"} // 排序字段必须唯一,这里用_id兜底 ] }假设返回的最后一条文档的排序值是
["2024-05-20T12:00:00Z", "12345"]后续分页查询:用
search_after参数传入上一页最后一条的排序值,获取下一页精确的10条数据GET /your_index/_search { "size": 10, "query": { "match_all": {} }, "search_after": ["2024-05-20T12:00:00Z", "12345"], "sort": [ {"create_time": "desc", "_id": "asc"} // 排序规则必须和第一次完全一致 ] }
2. 备选方案:scroll(适合批量导出,不适合实时分页)
scroll适合一次性批量导出数据,它基于查询时的快照,不会反映后续的数据更新,而且会占用集群资源,所以不适合用户交互类的分页场景。
步骤如下:
初始化scroll查询:获取第一页数据和
scroll_idGET /your_index/_search?scroll=1m // scroll上下文保留1分钟 { "size": 10, "query": { "match_all": {} } }获取后续分页:用
scroll_id获取下一页数据GET /_search/scroll { "scroll": "1m", "scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAA..." // 替换成实际的scroll_id }清理scroll上下文:用完后一定要清理,释放资源
DELETE /_search/scroll { "scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAA..." }
关键注意点
- 排序字段必须唯一且稳定:如果排序字段有重复值,可能导致分页时出现重复或遗漏的文档,建议用
_id作为排序的最后一个字段兜底。 - 如果有过滤条件,确保过滤逻辑精确:这样符合条件的文档总数是确定的,分页结果才会精准。
内容的提问来源于stack exchange,提问作者hamid

