过滤包含给定值的数组项

93

我有一组类似以下的文件:

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

如标题所述:是否有一种方法可以使用Nest过滤包含任何给定标签的所有文档?

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

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

5个回答

84

elasticsearch 2.0.1:

还有terms query可以帮你省去一些工作。这是来自文档的例子:

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

在幕后它构建布尔should语句。因此,基本上与上面的内容相同,只是更短。

还有一个对应的terms过滤器

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

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

标签数量越多,这可能会导致长度的相当大的差异。


1
我在让这个工作上遇到了麻烦。您介意在这里检查一下吗?http://stackoverflow.com/questions/32252789/elastic-search-rails-combine-multi-match-and-filter - user1571609
23
"minimum_should_match"已被弃用并将失败。 - Ain Tohvri
1
@AinTohvri 实际上在 Elasticsearch 2.0.1 中,minimum_should_match 仍然有效,并且官方文档没有将其标记为已弃用。 - Sinux
这有点取决于您使用的elasticsearch版本。但在大多数情况下,您只需要否定条件即可。例如,如果您在布尔查询的mustNot子句中使用完全相同的“terms”条件,则会搜索所有不具有任何标签的文档。 - slawek
minimum_should_match现在只是terms_set查询的一部分。 - Jason Smiley
显示剩余2条评论

70

编辑:下面的bitset内容可能是一段有趣的阅读,但是答案本身有点过时。在2.x版本中,某些功能正在发生变化。此外,Slawek在另一个回答中指出,terms查询是在这种情况下DRY(不重复原则)搜索的简单方法。最佳实践已在最后进行了重构。—nz

您可能需要一个布尔查询(或更可能与另一个查询一起使用过滤器),其中包含一个should子句。

布尔查询具有三个主要属性:mustshouldmust_not。每个属性都接受另一个查询或查询数组。这些子句名称相当自解释;在您的情况下,should子句可以指定一个过滤器列表,其中任何一个匹配项将返回您要查找的文档。

来自文档的摘录:

在没有must子句的布尔查询中,一个或多个should子句必须匹配文档。可以使用minimum_should_match参数设置应匹配的最小子句数。

以下是该Bool查询在独立情况下的示例:

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

这里是布尔查询作为筛选器在更常见的过滤查询中的另一个示例:

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

无论你将 Bool 用作查询(例如,影响匹配的得分),还是用作过滤器(例如,减少随后被评分或过滤的命中数)都是主观的,取决于你的需求。

通常情况下,与使用 Or 过滤器 相比,最好使用 Bool,除非你有理由使用 And/Or/Not(确实存在这样的理由)。Elasticsearch 博客提供了有关每种实现方式的更多信息,并且给出了何时可能更喜欢 Bool 而不是 And/Or/Not 以及反之的好例子。

Elasticsearch 博客:All About Elasticsearch Filter Bitsets

更新为重新构造的查询...

现在,把所有那些东西都放到一边,terms 查询是以上所有内容的简化版。它在内部处理了正确的查询类型,使用 minimum_should_match 选项时与 bool + should 的行为相同,总体上更加简洁。

以下是稍微重构一下的最后一个查询:

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

9
minimum_should_match 现已废弃。 - Josh Bedo
如果您需要常规的“或”行为,并且还通过另一个数组进行筛选,则“minimum_should_match”无法解决问题。 - Innokenty

24

虽然这是一个老问题,但最近我自己遇到了这个问题,这里的一些答案现在已经过时了(正如评论所指出的)。因此,为了让其他可能会遇到这个问题的人受益:

可以使用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 将执行全文搜索(即使用分析过的字符串)。如果你将该字段索引为keyword,则将执行使用“非分析”字符串的关键字搜索。这可能会产生巨大的实际影响,因为分析过的字符串是经过预处理的(小写化、标点符号删除等)。请参见(https://www.elastic.co/guide/en/elasticsearch/guide/master/term-vs-full-text.html

为避免这些问题,字符串字段已拆分为两种新类型:text,应用于全文搜索;keyword,应用于关键字搜索。(https://www.elastic.co/blog/strings-are-dead-long-live-strings


8

对于那些在2020年以后查看此内容的人,您可能会注意到接受的答案已经过时了,但是可以使用类似的方法组合使用terms_setminimum_should_match_script来解决。

请查看SO线程中此详细回答


2

您应该使用Terms Query进行 IT 技术相关内容的查询。

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

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