写在前面
通过from,size来进行分页查询时,如下:
当from比较大时会有深度分页问题,问题产生的核心是coordinate node需要从每个分片中获取from+size
条数据,当from比较大,整体需要获取的数据量也会比较大,如下图:
所以es深度分页问题的核心就在于每个分片多需要返回from+size
条数据,所以,如果能解决这个问题,也就解决深度分页的问题了。
但es针对from size方式的深度分页问题也是提供了一定的应对措施的,比如通过参数index.max_result_window
,默认是10000条,如下超过1万条时将会报错:
- 1
- 2
并且,为了更好的解决深度分页问题,es同时提供了search after和scroll两种方式来解决深度分页,其中前者是通过定位到某个数据的方式来解决,后者是通过创建快照的方式来解决。
分别看下。
1:search after
search after是实时分页,并且要求sort的字段必须是唯一的(多个sort字段组合在一起唯一也可)
,所以一般我们在使用search after时,会在不影响业务要求的排序基础上将_id
也加上去,如下:
- 格式
{"size": "size值","query": {具体的chaxun},"search_after": [上一个sort 的结果]",”sort“: [sort数组]
}
- 实例
为了测试,我们先来准备测试数据:
DELETE usersPOST users/_doc
{"name":"user1","age":10}POST users/_doc
{"name":"user2","age":11}POST users/_doc
{"name":"user3","age":12}POST users/_doc
{"name":"user4","age":13}// "count" : 4,
GET users/_count
- 查询第一页的数据
此时需要使用from size来查询
POST users/_search
{"from": 0,"size": 1,"query": {"match_all": {}},"sort": [{"age": "desc"},{"_id": "asc"}]
}
取结果中的sort值作为查询下一页数据的入参:
- 查询下一页
POST users/_search
{"size": 1,"query": {"match_all": {}},"search_after": [13,"z-cxE44BbPrZSKsI0wh6"],"sort": [{"age": "desc"},{"_id": "asc"}]
}
如此重复直到没有下一页:
search after通过每次从每个分片获取from+size的数据量变为size来解决了深度分页的问题,如下图:
2:scroll api
scroll api通过快照的方式来解决深度分页问题,即第一次查询时会生成一个全量数据的快照,因此快照生成后的数据将无法被查询,这种方式一般用于数据导出等场景中。
看例子。
- 准备数据
DELETE usersPOST users/_doc
{"name":"user1","age":10}POST users/_doc
{"name":"user2","age":11}POST users/_doc
{"name":"user3","age":12}POST users/_doc
{"name":"user4","age":13}
- 创建scroll快照,五分钟失效
POST users/_search?scroll=5m
{"size": 1,"query": {"match_all": {}}
}
- 查询下一页
POST /_search/scroll
{"scroll": "1m","scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAhesWUk9pVDk4SUdSUXEyRGlhc21kVDJUZw=="
}
一直查询到没有下一页:
再来插入一条:
POST users/_doc
{"name":"user5","age":14}
因为读的是快照,所以是查不到的。