【问题标题】:How does search_after work in elastic search?search_after 在弹性搜索中如何工作?
【发布时间】:2021-06-25 08:31:40
【问题描述】:

我一直在尝试将 Elasticsearch 用于我们的应用程序,但是分页限制为 10k 对我们来说实际上是一个问题,并且由于必须超时问题,滚动 API 也不是推荐的选择。

我发现 Elasticsearch 有一个叫做 search_after 的东西,它是支持深度分页的理想解决方案。我一直试图从文档中理解它,但它有点令人困惑,无法清楚地理解它是如何工作的。

假设,我的文档中有三列,id, first_name, last_name,这里的 ID 是唯一的主键。

{
    "size": 10,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    },
    "sort": [
        {"id": "asc"}      
    ]
}

我可以使用上述查询来使用 search_after 功能吗?我在他们的文档中读到,我们必须在排序中使用多个唯一值,而不仅仅是一个 (ID),但正如您所知,在我的数据集中我只有 ID 是唯一的。 如何在我的数据集示例中使用 search_after?

如果我使用一个独特的决胜局进行排序,我无法理解所述问题?有人可以用外行的方式帮助解释一下吗?

https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-search-after.html

每个文档都有一个唯一值的字段应用作 排序规范的决胜局。否则排序顺序为 具有相同排序值的文档将是未定义的,并且可以 导致结果丢失或重复。 _id 字段具有唯一值 每个文档,但不建议将其用作决胜局 直接地。请注意,search_after 会查找第一个文档 完全或部分匹配 tiebreaker 提供的值。因此,如果一个 文档的决胜局值为“654323”,您 search_after “654”它仍然会匹配该文档并返回找到的结果 在它之后。 doc 值在此字段上被禁用,因此对其进行排序 需要在内存中加载大量数据。相反,建议 复制(客户端或使用设置的摄取处理器)的内容 另一个启用了文档值的字段中的 _id 字段并使用 这个新字段作为排序的决胜局。

【问题讨论】:

  • 据我了解,只要字段值是唯一的,您就可以只对一个字段使用排序。当您想根据某些非唯一字段对文档进行排序时,您需要添加多个排序字段(一个具有唯一值作为辅助排序的字段)作为决胜局。
  • @Pramod 从文档中,他们提到仅使用 _ID 字段并不理想,因为我猜 search_after 会进行部分匹配而不是完全匹配。这似乎是他们在文档页面中解释的内容。我想知道如何解决这个问题?
  • 我认为您提到的Id 字段与_id 字段不同。是的,不建议在排序中使用_id,因为它需要在内存中加载大量数据。您可以将_id 字段复制为文档的id 字段并用于排序。
  • @Pramod 抱歉,ID 字段与 _id 字段不同。这是一个错字。他们正在讨论的问题呢,Therefore if a document has a tiebreaker value of "654323" and you search_after for "654" it would still match that document and return results found after it.

标签: elasticsearch elastic-stack


【解决方案1】:

在您的情况下,如果您的 id 字段包含唯一值并且类型为 keyword(或数字),那么您绝对没问题,并且可以使用它来使用 search_after 进行分页。

所以第一个电话将是您的问题:

{
    "size": 10,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    },
    "sort": [
        {"id": "asc"},
        {"score": "desc"}      
    ]
}

在您的回复中,您需要查看最后一次点击并从最后一次点击中获取 sort 值:

{
    "_index" : "myindex",
    "_type" : "_doc",
    "_id" : "100000012",
    "_score" : null,
    "_source": { ... },
    "sort" : [
      "100000012",                                <--- take this
      "98"                                        <--- take this
    ]
}

然后在下一次搜索调用中,您将在 search_after 中指定该值

{
    "size": 10,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    },
    "search_after": [ "100000012", "98" ],        <--- add this
    "sort": [
        {"id": "asc"}      
    ]
}

下一个结果集的第一个命中将是id: 100000013。就是这样。没有别的了。

如果您总是使用完整的id 值进行排序,您所指出的问题与您无关。它的工作方式是您始终使用上一个结果中的最后一个 id 值。如果您要添加"search_after": ["1000"],那么您就会遇到他们提到的问题,但您没有理由这样做。

【讨论】:

  • 太棒了,很高兴它有帮助!
  • 如果我还有一个名为score 的列(字段),那么 search_after 会起作用,每个文档的得分为 0 -100,问题是可能存在得分相同的文档。我想要分数降序排列的结果文档。在这种情况下,我是否需要在排序中同时使用 ID 和分数。如果我这样做,它将获得更多优先权。我的结果会根据 id 或 score 排序吗?之后我可以使用搜索吗?
  • 如果您使用两个排序字段进行搜索(首先是 id,其次是 score),那么结果中的 sort 数组将有两个值(["100000012", "98"]),您需要同时使用这两个值在search_after 中进行下一个查询。但是由于id 具有独特的价值,您不会冒丢失任何数据的风险。我已经相应地更新了我的答案
  • 只要有id 充当决胜局的字段,就可以交换排序字段
  • 太棒了,很高兴它有帮助!我会尽快检查您的下一个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
  • 2021-08-21
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
相关资源
最近更新 更多