写在前面
通过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 users
POST 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 users
POST 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}
因为读的是快照,所以是查不到的。