赞
踩
search_after 分页的方式是根据上一页的最后一条数据来确定下一页的位置,同时在分页请求的过程中,如果有索引数据的增删改查,这些变更也会实时的反映到游标上。但是需要注意,因为每一页的数据依赖于上一页最后一条数据,所以无法跳页请求。
为了找到每一页最后一条数据,每个文档必须有一个全局唯一值,官方推荐使用 _uid 作为全局唯一值,其实使用业务层的 id 也可以。
上面的请求会为每一个文档返回一个包含sort排序值的数组。这些sort排序值可以被用于 search_after 参数里以便抓取下一页的数据。比如,我们可以使用最后的一个文档的sort排序值,将它传递给 search_after 参数:
注意:当我们使用search_after时,from值必须设置为0或者-1。
search_after缺点是不能够随机跳转分页,只能是一页一页的向后翻,并且需要至少指定一个唯一不重复字段来排序。它与滚动API非常相似,但与它不同,search_after参数是无状态的,它始终针对最新版本的搜索器进行解析。因此,排序顺序可能会在步行期间发生变化,具体取决于索引的更新和删除。
search_after 查询本质:使用前一页中的一组排序值来检索匹配的下一页。
前置条件:使用 search_after 要求后续的多个请求返回与第一次查询相同的排序结果序列。也就是说,即便在后续翻页的过程中,可能会有新数据写入等操作,但这些操作不会对原有结果集构成影响。
可以创建一个时间点 Point In Time(PIT)保障搜索过程中保留特定事件点的索引状态。
Point In Time(PIT)是 Elasticsearch 7.10 版本之后才有的新特性。
PIT的本质:存储索引数据状态的轻量级视图。
如下示例能很好的解读 PIT 视图的内涵。
POST kibana_sample_data_logs/_pit?keep_alive=1m
获取数据量 14074
POST kibana_sample_data_logs/_count
新增一条数据
POST kibana_sample_data_logs/_doc/14075
{
"test":"just testing"
}
数据总量为 14075
POST kibana_sample_data_logs/_count
查询PIT,数据依然是14074,说明走的是之前时间点的视图的统计
POST /_search
{
"track_total_hits": true,
"query": {
"match_all": {}
},
"pit": {
"id": "48myAwEXa2liYW5hX3NhbXBsZV9kYXRhX2xvZ3MWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAWdG1TOWFMTF9UdTZHdVZDYmhoWUljZwAAAAAAAAEN3RZGOFJCMGVrZVNndTk3U1I0SG81V3R3AAEWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAA"
}
}
有了 PIT,search_after 的后续查询都是基于 PIT 视图进行,能有效保障数据的一致性。
search_after 分页查询可以简单概括为如下几个步骤。
步骤 1:创建 PIT 视图,这是前置条件不能省。
POST kibana_sample_data_logs/_pit?keep_alive=5m
返回结果如下:
{
"id" : "48myAwEXa2liYW5hX3NhbXBsZV9kYXRhX2xvZ3MWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAWdG1TOWFMTF9UdTZHdVZDYmhoWUljZwAAAAAAAAEg5RZGOFJCMGVrZVNndTk3U1I0SG81V3R3AAEWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAA"
}
keep_alive=5m,类似scroll的参数,代表视图保留时间是 5 分钟。
超过 5 分钟执行会报错如下:
{
"type": "search_context_missing_exception",
"reason": "No search context found for id [91600]"
}
步骤 2:创建基础查询语句,这里要设置翻页的条件。
GET /_search
{
"size":10,
"query": {
"match" : {
"host" : "elastic"
}
},
"pit": {
"id": "48myAwEXa2liYW5hX3NhbXBsZV9kYXRhX2xvZ3MWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAWdG1TOWFMTF9UdTZHdVZDYmhoWUljZwAAAAAAAAEg5RZGOFJCMGVrZVNndTk3U1I0SG81V3R3AAEWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAA",
"keep_alive": "1m"
},
"sort": [
{"response.keyword": "asc"}
]
}
设置了PIT,检索时候就不需要再指定索引。
id 是基于步骤1 返回的 id 值。
排序 sort 指的是:按照哪个关键字排序。
在每个返回文档的最后,会有两个结果值,如下所示:
{
"sort": [
"200",
4
]
}
其中,“200”就是我们指定的排序方式:基于 {“response.keyword”: “asc”} 升序排列。
而 4 代表什么含义呢?
4 代表——隐含的排序值,是基于_shard_doc 的升序排序方式。
官方文档把这种隐含的字段叫做:tiebreaker (决胜字段),tiebreaker 等价于_shard_doc。
tiebreaker 本质含义:每个文档的唯一值,确保分页不会丢失或者分页结果数据出现重复(相同页重复或跨页重复)。
步骤3:实现后续翻页。
GET /_search
{ "size": 10, "query": { "match" : { "host" : "elastic" } }, "pit": { "id": "48myAwEXa2liYW5hX3NhbXBsZV9kYXRhX2xvZ3MWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAWdG1TOWFMTF9UdTZHdVZDYmhoWUljZwAAAAAAAAEg5RZGOFJCMGVrZVNndTk3U1I0SG81V3R3AAEWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAA", "keep_alive": "1m" }, "sort": [ {"response.keyword": "asc"} ], "search_after": [ "200", 4 ] }
后续翻页都需要借助 search_after 指定前一页的最后一个文档的 sort 字段值。
如下代码所示:
{
"search_after": [
"200",
4
]
}
显然,search_after 查询仅支持向后翻页。
search_after 优点
不严格受制于 max_result_window,可以无限制往后翻页。
ps:不严格含义:单次请求值不能超过 max_result_window;但总翻页结果集可以超过。
search_after 缺点
只支持向后翻页,不支持随机翻页。
search_after 适用场景
类似:今日头条分页搜索 https://m.toutiao.com/search
不支持随机翻页,更适合手机端应用的场景。
相比于 From + size 和 search_after 返回一页数据,Scroll API 可用于从单个搜索请求中检索大量结果(甚至所有结果),其方式与传统数据库中游标(cursor)类似。
如果把 From + size 和 search_after 两种请求看做近实时的请求处理方式,那么 scroll 滚动遍历查询显然是非实时的。数据量大的时候,响
应时间可能会比较长。
scroll 核心执行步骤如下:
步骤 1:指定检索语句同时设置 scroll 上下文保留时间。
实际上,scroll 已默认包含了 search_after 的PIT 的视图或快照功能。
从 Scroll 请求返回的结果反映了发出初始搜索请求时索引的状态,类似在那一个时刻做了快照。随后对文档的更改(写入、更新或删除)只会影响以后的搜索请求。
POST kibana_sample_data_logs/_search?scroll=3m
{
"size": 100,
"query": {
"match": {
"host": "elastic"
}
}
}
步骤 2:向后翻页继续获取数据,直到没有要返回的结果为止。
POST _search/scroll
{
"scroll" : "3m",
"scroll_id":"FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFkY4UkIwZWtlU2d1OTdTUjRIbzVXdHcAAAAAAAGmkBZ0bVM5YUxMX1R1Nkd1VkNiaGhZSWNn"
}
scroll_id 值是步骤 1 返回的结果值。
scroll 查询优点
支持全量遍历。
ps:单次遍历的 size 值也不能超过 max_result_window 大小。
scroll 查询缺点
响应时间非实时。
保留上下文需要足够的堆内存空间。
scroll 查询适用场景
全量或数据量很大时遍历结果数据,而非分页查询。
官方文档强调:不再建议使用scroll API进行深度分页。如果要分页检索超过 Top 10,000+ 结果时,推荐使用:PIT + search_after。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。