根据一个字段值,将 Elasticsearch 的结果过滤为仅包含唯一文档。

19

我的所有文档都有一个uid字段,其中包含将文档链接至用户的ID。存在多个具有相同uid的文档。

我想对所有文档执行搜索,并仅返回每个唯一uid的最高评分文档。

选择相关文档的查询是一个简单的multi_match查询。

2个回答

23

您需要使用top_hits聚合。

对于您的具体情况:

{
  "query": {
    "multi_match": {
      ...
    }
  },
  "aggs": {
    "top-uids": {
      "terms": {
        "field": "uid"
      },
      "aggs": {
        "top_uids_hits": {
          "top_hits": {
            "sort": [
              {
                "_score": {
                  "order": "desc"
                }
              }
            ],
            "size": 1
          }
        }
      }
    }
  }
}

上述查询执行了您的multi_match查询,并根据uid聚合结果。对于每个uid存储桶,它只返回一个结果,但在存储桶中的所有文档按_score得分进行降序排序后返回。


有没有一种好的方法来分页浏览结果桶? - TheHippo
这个问题似乎在github上有很长的讨论。而且这不是唯一一个讨论这个问题的问题。 - Andrei Stefan

18
ElasticSearch 5.3中,他们添加了对字段折叠的支持。你应该能够执行类似以下的操作:
GET /_search
{
  "query": {
    "multi_match" : {
      "query":    "this is a test", 
      "fields": [ "subject", "message", "uid" ] 
    }
  },
  "collapse" : {
    "field" : "uid" 
  },
  "size": 20,
  "from": 100
}

使用字段折叠而不是顶部命中聚合的好处在于,您可以在字段折叠中使用分页。

这很好,但不适用于文本字段。 - Austin Poulson
1
正确,查询可以,只有你折叠的字段不能。从文档中可以看到,“用于折叠的字段必须是启用了doc_values的单值关键字或数字字段”。因此,它适用于像UUID或URL等内容。如果适用于数据,则可以使用多字段方法,如https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-fields.html中所述,将该字段作为文本和关键字都可用。 - Chase

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接