《Elastic Stack 实战手册》——三、产品能力——3.4.入门篇——3.4.2.Elasticsearch基础应用——3.4.2.14.分页搜索(上) https://developer.aliyun.com/article/1230187
search_after
如果说 scroll 是把上下文保存在服务端,而 search_after 要求数据中存在一个无重复,可以用于排序的字段,需要客户端每次传入上次查到的最后结果,然后获取其随后的数据。
由于随后的请求每次都是查询出来的,如果数据发生变化,就可能出现跨页面结果不一致的情况,为了防止这种情况,需要在请求中加一个参数来设置当前的索引状态保留时间。
POST /my-index-000001/_pit?keep_alive=1m
PIT 是 point in time 的简写,他是一个轻量级的视图。上述请求返回一个 ID:
{ "id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==" }
随后的请求中你需要带上他。可以通过下面的方式,获取第一页的结果,其中的特别之处在于,要指定进行排序的字段:
GET /_search { "size": 10000, "query": { "match" : { "user.id" : "elkbee" } }, "pit": { "id": "46ToAwMDaWR5BXV1aWQyKwZub2RlXzMAAAAAAAAAACoBYwADaWR4BXV1aWQxAgZub2RlXzEAAAAAAAAAAAEBYQADaWR5BXV1aWQyKgZub2RlXzIAAAAAAAAAAAwBYgACBXV1aWQyAAAFdXVpZDEAAQltYXRjaF9hbGw_gAAAAA==", "keep_alive": "1m" }, "sort": [ {"@timestamp": "asc"} ] }
在返回结果中,会携带 sort 字段的值,
{ "hits" : { "hits" : [ { "sort" : [ 4294967298 ] } ] } }
你需要在下次请求的时候带上他:
GET /_search { "size": 10000, "query": ... "pit": { "id": ... "keep_alive": ... }, "sort": [ {"@timestamp": "asc"} ], "search_after": [ 4294967298 ] }
类似 scroll,pit 请求返回的 ID 也可以手工清理。
最后我们总结一下每种分页方式的特点:
l from+size 支持跳页,不适合深分页。
l scroll 不支持跳页,适合拉取大量数据,不适合大量并发。
l search_after 不支持跳页,适合拉取大量数据。
scroll 和 search_after 都可以用于深分页,search_after 需要提供一个主键字段进行排序,默认为 _shard_doc,它是 shard index 与 Lucene 内部 ID 的组合值。在服务端保存的上下文要比 scroll 小,目前官方推荐使用 search_after 代替 scroll。