过滤数组包含任何给定值的项目

Filter items which array contains any of given values

我有一组文档,例如

{
    tags:['a','b','c']
    // ... a bunch properties
}

如标题所述:有没有办法使用 Nest 过滤包含任何给定标签的所有文档?

例如,上面的记录将匹配 ['c','d']

或者我应该手动构建多个 "OR" 吗?

编辑:下面的 bitset 内容可能很有趣,但答案本身有点过时。 2.x 中的某些功能正在发生变化。 Slawek 在另一个答案中也指出,在这种情况下,terms 查询是干掉搜索的一种简单方法。最后重构为当前的最佳实践。 —nz

您可能需要 Bool Query (or more likely Filter 和另一个查询),以及 should 子句。

bool 查询具有三个主要属性:mustshouldmust_not。其中每一个都接受另一个查询或查询数组。子句名称是不言自明的;在您的情况下,should 子句可以指定一个列表过滤器,与其中任何一个的匹配都将 return 您要查找的文档。

来自文档:

In a boolean query with no must clauses, one or more should clauses must match a document. The minimum number of should clauses to match can be set using the minimum_should_match parameter.

这里有一个 Bool 查询孤立的例子:

{
  "bool": {
    "should": [
      { "term": { "tag": "c" }},
      { "term": { "tag": "d" }}
    ]
  }
}

这里是 Bool 查询的另一个示例,作为更通用 Filtered Query:

中的过滤器
{
  "filtered": {
    "query": {
      "match": { "title": "hello world" }
    },
    "filter": {
      "bool": {
        "should": [
          { "term": { "tag": "c" }},
          { "term": { "tag": "d" }}
        ]
      }
    }
  }
}

是否将 Bool 用作查询(例如,影响匹配分数)或用作过滤器(例如,减少随后被评分或 post-过滤的命中)是主观的, 取决于您的要求。

通常最好使用 Bool 而不是 Or Filter,除非您有使用 And/Or/Not 的理由(确实存在这样的理由)。 Elasticsearch 博客提供了有关每种不同实现的更多信息,以及您可能更喜欢 Bool 而不是 And/Or/Not 的好例子,反之亦然。

Elasticsearch 博客:All About Elasticsearch Filter Bitsets

更新重构查询...

现在,所有 that 都已完成,terms 查询是上述所有内容的 DRYer 版本。它在后台就查询类型做了正确的事情,它的行为与使用 minimum_should_match 选项的 bool + should 相同,总体上更简洁一些。

这是对最后一个查询进行了一些重构:

{
  "filtered": {
    "query": {
      "match": { "title": "hello world" }
    },
    "filter": {
      "terms": {
        "tag": [ "c", "d" ],
        "minimum_should_match": 1
      }
    }
  }
}

弹性搜索 2.0.1:

还有 terms query 应该可以为您省去一些工作。这里的例子来自文档:

{
  "terms" : {
      "tags" : [ "blue", "pill" ],
      "minimum_should_match" : 1
  }
}

在引擎盖下它构造了布尔值 should。所以它基本上和上面一样,但更短。

还有对应的terms filter.

因此,总结您的查询可能如下所示:

{
  "filtered": {
    "query": {
      "match": { "title": "hello world" }
    },
    "filter": {
      "terms": {
        "tags": ["c", "d"]
      }
    }
  }
}

如果标签数量更多,长度可能会有很大差异。

虽然这是一个老问题,但我最近 运行 亲自解决了这个问题,这里的一些答案现在已被弃用(正如评论所指出的)。因此,为了其他可能在这里跌跌撞撞的人的利益:

term 查询可用于查找反向索引中指定的确切术语:

{
  "query": {
   "term" : { "tags" : "a" }
} 

来自文档 https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html

或者,您可以使用 terms 查询,它将所有文档与给定数组中指定的任何项目进行匹配:

{
  "query": {
   "terms" : { "tags" : ["a", "c"]}
} 

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html

需要注意的一个问题(这让我很困惑)- 定义文档的方式也会有所不同。如果您正在搜索的字段已被索引为 text 类型,那么 Elasticsearch 将执行全文搜索(即使用 analyzed 字符串)。

如果您将该字段编入索引为 keyword,则会使用 'non-analyzed' 字符串执行关键字搜索。这可能会产生巨大的实际影响,因为已分析的字符串经过预处理(小写、标点符号删除等)请参阅 (https://www.elastic.co/guide/en/elasticsearch/guide/master/term-vs-full-text.html)

To avoid these issues, the string field has split into two new types: text, which should be used for full-text search, and keyword, which should be used for keyword search. (https://www.elastic.co/blog/strings-are-dead-long-live-strings)

你应该使用Terms Query

{
    "query" : {
        "terms" : {
            "tags" : ["c", "d"]
        }
    }
}

对于那些在 2020 年查看此内容的人,您可能会注意到已接受的答案在 2020 年已被弃用,但可以使用 terms_setminimum_should_match_script 组合使用类似的方法。

请参阅 SO 线程

中的详细答案