Link Search Menu Expand Document Documentation Menu

结果分页

您可以使用以下方法在 OpenSearch 中对搜索结果进行分页

  1. fromsize 参数
  2. scroll 搜索》操作
  3. search_after 参数
  4. 结合 search_after 的时间点

fromsize 参数

fromsize 参数每次返回一页结果。

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 中指定 fromsize 参数:

GET shakespeare/_search?from=0&size=10

如果您只指定 size 参数,from 参数将默认为 0。

查询结果深处的页面可能会对性能产生显著影响,因此 OpenSearch 将此方法限制为 10,000 个结果。

fromsize 参数是无状态的,因此结果基于最新的可用数据。这可能导致分页不一致。例如,假设用户停留在第一页结果,然后导航到第二页。在此期间,一个与用户搜索相关的新文档被索引并显示在第一页。在这种情况下,第一页的最后一个结果会被推到第二页,用户会看到重复的结果(即,第一页和第二页都显示该最后一个结果)。

使用 scroll 操作进行一致的分页。scroll 操作会在一定时间内保持搜索上下文开放。在此期间,任何数据更改都不会影响结果。

fromsize 参数允许您对搜索结果进行分页,但每次限制为 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 中首选的分页方法,特别适用于深度分页。它绕过了所有其他方法的限制,因为它操作的是一个时间上冻结的数据集,不受查询的约束,并且支持向前和向后的一致分页。要了解更多信息,请参阅时间点

剩余 350 字符

有问题?

想做出贡献?