结果分页
您可以使用以下方法在 OpenSearch 中对搜索结果进行分页
from
和 size
参数
from
和 size
参数每次返回一页结果。
from
参数是您希望开始显示结果的文档编号。size
参数是您希望显示的结果数量。两者结合使用,您可以返回搜索结果的一个子集。
例如,如果 size
的值为 10 且 from
的值为 0,您将看到前 10 个结果。如果您将 from
的值更改为 10,您将看到接下来的 10 个结果(因为结果是零索引的)。因此,如果您想从第 11 个结果开始查看,from
必须是 10。
GET shakespeare/_search
{
"from": 0,
"size": 10,
"query": {
"match": {
"play_name": "Hamlet"
}
}
}
使用以下公式根据页码计算 from
参数:
from = size * (page_number - 1)
每次用户选择下一页结果时,您的应用程序都需要使用递增的 from
值运行相同的搜索查询。
您还可以在搜索 URI 中指定 from
和 size
参数:
GET shakespeare/_search?from=0&size=10
如果您只指定 size
参数,from
参数将默认为 0。
查询结果深处的页面可能会对性能产生显著影响,因此 OpenSearch 将此方法限制为 10,000 个结果。
from
和 size
参数是无状态的,因此结果基于最新的可用数据。这可能导致分页不一致。例如,假设用户停留在第一页结果,然后导航到第二页。在此期间,一个与用户搜索相关的新文档被索引并显示在第一页。在这种情况下,第一页的最后一个结果会被推到第二页,用户会看到重复的结果(即,第一页和第二页都显示该最后一个结果)。
使用 scroll
操作进行一致的分页。scroll
操作会在一定时间内保持搜索上下文开放。在此期间,任何数据更改都不会影响结果。
Scroll 搜索
from
和 size
参数允许您对搜索结果进行分页,但每次限制为 10,000 个结果。
例如,如果您需要从机器学习作业请求超过 1 PB 的数据量,请改用 scroll
操作。scroll
操作允许您请求无限数量的结果。
要使用 `scroll` 操作,请在请求头中添加一个 `scroll` 参数,其中包含一个搜索上下文,告诉 OpenSearch 您需要保持滚动多长时间。此搜索上下文需要足够长以处理单个批次的结果。
要设置每个批次返回的结果数量,请使用 size
参数:
GET shakespeare/_search?scroll=10m
{
"size": 10000
}
OpenSearch 缓存结果并返回一个 `scroll ID`,您可以使用它来批量访问结果:
"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAAUWdmpUZDhnRFBUcWFtV21nMmFwUGJEQQ=="
将此 `scroll ID` 传递给 scroll
操作以获取下一批结果:
GET _search/scroll
{
"scroll": "10m",
"scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAAUWdmpUZDhnRFBUcWFtV21nMmFwUGJEQQ=="
}
使用此 `scroll ID`,只要搜索上下文保持开放,您就可以获取每批 10,000 个结果。通常,`scroll ID` 在请求之间不会改变,但它可能改变,因此请务必始终使用最新的 `scroll ID`。如果您未在设置的搜索上下文内发送下一个滚动请求,scroll
操作将不会返回任何结果。
如果您预期有数十亿个结果,请使用切片滚动。切片允许您对同一个请求并行执行多个滚动操作。设置 `scroll` 的 ID 和最大切片数:
GET shakespeare/_search?scroll=10m
{
"slice": {
"id": 0,
"max": 10
},
"query": {
"match_all": {}
}
}
使用单个 `scroll ID`,您会收到 10 个结果。您最多可以有 10 个 ID。使用 ID 等于 1 执行相同的命令:
GET shakespeare/_search?scroll=10m
{
"slice": {
"id": 1,
"max": 10
},
"query": {
"match_all": {}
}
}
滚动完成后请关闭搜索上下文,因为它会持续消耗计算资源直到超时:
DELETE _search/scroll/DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAAcWdmpUZDhnRFBUcWFtV21nMmFwUGJEQQ==
示例响应
{
"succeeded": true,
"num_freed": 1
}
使用以下请求关闭所有打开的滚动上下文:
DELETE _search/scroll/_all
scroll
操作对应于一个特定的时间戳。它不考虑在该时间戳之后添加的文档作为潜在结果。
由于开放的搜索上下文会消耗大量内存,我们建议您不要将 scroll
操作用于不需要保持搜索上下文开放的频繁用户查询。相反,请使用 sort
参数和 search_after
参数来滚动用户查询的响应。
search_after
参数
search_after
参数提供了一个实时游标,它使用上一页的结果来获取下一页的结果。它与 scroll
操作相似,旨在并行滚动许多查询。您只能在应用排序时使用 search_after
。
例如,以下查询按发言编号和 ID 对剧本“哈姆雷特”中的所有行进行排序,并检索前三个结果:
GET shakespeare/_search
{
"size": 3,
"query": {
"match": {
"play_name": "Hamlet"
}
},
"sort": [
{ "speech_number": "asc" },
{ "_id": "asc" }
]
}
响应包含每个文档的 sort
值数组:
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 4244,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "shakespeare",
"_id" : "32435",
"_score" : null,
"_source" : {
"type" : "line",
"line_id" : 32436,
"play_name" : "Hamlet",
"speech_number" : 1,
"line_number" : "1.1.1",
"speaker" : "BERNARDO",
"text_entry" : "Whos there?"
},
"sort" : [
1,
"32435"
]
},
{
"_index" : "shakespeare",
"_id" : "32634",
"_score" : null,
"_source" : {
"type" : "line",
"line_id" : 32635,
"play_name" : "Hamlet",
"speech_number" : 1,
"line_number" : "1.2.1",
"speaker" : "KING CLAUDIUS",
"text_entry" : "Though yet of Hamlet our dear brothers death"
},
"sort" : [
1,
"32634"
]
},
{
"_index" : "shakespeare",
"_id" : "32635",
"_score" : null,
"_source" : {
"type" : "line",
"line_id" : 32636,
"play_name" : "Hamlet",
"speech_number" : 1,
"line_number" : "1.2.2",
"speaker" : "KING CLAUDIUS",
"text_entry" : "The memory be green, and that it us befitted"
},
"sort" : [
1,
"32635"
]
}
]
}
}
您可以使用最后一个结果的 sort
值,通过 search_after
参数检索下一个结果:
GET shakespeare/_search
{
"size": 10,
"query": {
"match": {
"play_name": "Hamlet"
}
},
"search_after": [ 1, "32635"],
"sort": [
{ "speech_number": "asc" },
{ "_id": "asc" }
]
}
与 scroll
操作不同,search_after
参数是无状态的,因此文档顺序可能会因为文档的索引或删除而改变。
结合 search_after
的时间点
结合 search_after
的时间点 (PIT) 是 OpenSearch 中首选的分页方法,特别适用于深度分页。它绕过了所有其他方法的限制,因为它操作的是一个时间上冻结的数据集,不受查询的约束,并且支持向前和向后的一致分页。要了解更多信息,请参阅时间点。