前言
在 ES 中,我们通常使用 from, size 进行分页。
为了避免使用 from, size 分页太深,或者一次请求过多数据。默认情况下,分页不能超过 1w 条。
如果需要深度分页的场景,一般使用 search_after、PIT、scroll API 解决深度分页性能问题。
有关深度分页的内容,也可自行阅读 ES 深度分页官网
search after
search_after 可用于解决深度分页问题。但是如果在使用 search after 时,新写入文档,结果的顺序可能会改变,会导致页面之间的结果不一致。
我们先来看,search after 如何使用
写入文档
PUT test11/_bulk
{"index": {}}
{"name": "java"}
{"index": {}}
{"name": "golang"}
{"index": {}}
{"name": "python"}
{"index": {}}
{"name": "php"}
{"index": {}}
{"name": "c"}
{"index": {}}
{"name": "c++"}
第一次搜索
GET test11/_search
{
"size":1,
"sort": [
{
"name.keyword": {
"order": "desc"
}
}
],
"query": {
"match_all": {}
}
}
第二次搜索
GET test11/_search
{
"size":1,
"sort": [
{
"name.keyword": {
"order": "desc"
}
}
],
"query": {
"match_all": {}
},
"search_after": ["python"]
}
search after 的值需要与 sort 字段相匹配
当禁用总命中跟踪时,search after 的性能会更好。例如
GET test11/_search
{
"size":1,
"sort": [
{
"name.keyword": {
"order": "desc"
}
}
],
"query": {
"match_all": {}
},
"track_total_hits": false,
"search_after": ["python"]
}
point in time(PIT)
search_after 无法某一段时间内的索引状态,因此当有新数据写入时,排序结果可能会不一致。
为了解决这个问题,我们可以使用 PIT。
PIT 可以保留一段时间内的索引状态。
接下来,我们来看如何使用
创建 PIT
在搜索之前,需要创建 PIT,并通过 keep_avlie 指定索引状态保留多久。
POST test11/_pit?keep_alive=1m
该查询会返回一个 id 字段,我们只要在下一次查询中,带上该字段即可。
使用 pit.id 进行翻页
可以注意到,使用 PIT,并不需要指定索引的名称
GET /_search
{
"size": 1,
"query": {
"match_all": {}
},
"pit": {
"id": "x6XoAwEGdGVzdDExFm96XzU5ZlJCUmhXVUVxZHdDMDNFNXcAFnVqRTBIUkNCUzNtZlZ5aW5GUHR2encAAAAAAABE69YWamdNZFZ1ZUpSSjI4WU93LUtkdE1UUQABFm96XzU5ZlJCUmhXVUVxZHdDMDNFNXcAAA==",
"keep_alive": "1m"
}
}
类似的,我们也可以禁用总命中跟踪,来提高查询效率
GET /_search
{
"size": 1,
"query": {
"match_all": {}
},
"track_total_hits": false,
"pit": {
"id": "x6XoAwEGdGVzdDExFm96XzU5ZlJCUmhXVUVxZHdDMDNFNXcAFnVqRTBIUkNCUzNtZlZ5aW5GUHR2encAAAAAAABE69YWamdNZFZ1ZUpSSjI4WU93LUtkdE1UUQABFm96XzU5ZlJCUmhXVUVxZHdDMDNFNXcAAA==",
"keep_alive": "1m"
}
}
关闭 PIT
keep_alive 结束时,PIT 会自动关闭,但保持时间点是有代价的,因此不使用时,应主动关闭。
DELETE /_pit/x6XoAwEGdGVzdDExFm96XzU5ZlJCUmhXVUVxZHdDMDNFNXcAFnVqRTBIUkNCUzNtZlZ5aW5GUHR2encAAAAAAABE69YWamdNZFZ1ZUpSSjI4WU93LUtkdE1UUQABFm96XzU5ZlJCUmhXVUVxZHdDMDNFNXcAAA==
scroll
scroll API 也可用于深度分页,在深度分页场景, ES 8 已经不推荐使用 scroll API, 而是推荐使用 PIT API 。
scroll API 同 PIT API 类似,也会保持一定时间的快照。避免在查询过程中,文档更新,而导致的不一致。
下面,我们来看下该 API 的基本使用。
初始搜索请求
POST /test11/_search?scroll=1m
{
"size": 1,
"query": {
"match_all": {}
}
}
请求会返回 _scorll_id 字段,可用于后续搜索
使用 Scroll ID 翻页
POST /_search/scroll
{
"scroll": "1m",
"scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmpnTWRWdWVKUkoyOFlPdy1LZHRNVFEAAAAAAETzBRZ1akUwSFJDQlMzbWZWeWluRlB0dnp3"
}
关闭 Scroll
与 PIT 类似,当不再使用 Scroll 时,应主动释放资源
DELETE /_search/scroll/FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmpnTWRWdWVKUkoyOFlPdy1LZHRNVFEAAAAAAETzBRZ1akUwSFJDQlMzbWZWeWluRlB0dnp3