筛选包含任何给定值的数组

时间:2015-01-17 16:30:58

标签: elasticsearch nest

我有一套像

这样的文件
{
    tags:['a','b','c']
    // ... a bunch properties
}

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

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

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

5 个答案:

答案 0 :(得分:51)

还有terms query这可以为你节省一些工作。这里来自docs的例子:

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

在引擎盖下,它构造了布尔值。所以它与上面的基本相同,但更短。

还有相应的terms filter

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

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

随着标签数量的增加,这可能会产生很大的差异。

答案 1 :(得分:41)

编辑:下面的bitset内容可能是一个有趣的读物,但答案本身有点陈旧。其中一些功能在2.x中发生了变化。另外,Slawek在另一个答案中指出terms查询是一种在这种情况下干扰搜索的简单方法。在最后重构当前的最佳实践。 -nz

您可能希望Bool Query(或更可能Filter与另一个查询一起使用),并带有should子句。

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

来自文档:

  

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

以下是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作为查询(例如,影响匹配的分数),或者作为过滤器(例如,减少随后被评分或后过滤的命中)是主观的,这取决于您的要求。

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

Elasticsearch博客:All About Elasticsearch Filter Bitsets

使用重构查询进行更新...

现在,在所有 的情况下,terms查询是上述所有内容的DRYer版本。它在底层的查询类型方面是正确的,它使用bool选项与should + minimum_should_match的行为相同,总体上更简洁一些。

这是最后一个查询重构了一点:

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

答案 2 :(得分:3)

尽管这是一个古老的问题,但我最近自己遇到了这个问题,并且不赞成此处的某些答案(正如评论所指出的那样)。因此,为了其他可能在这里绊倒的人的利益:

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

一个棘手的问题使我感到困惑-您如何定义文档也有所作为。如果您要搜索的字段已被索引为文本类型,则Elasticsearch将执行全文搜索(即使用analyzed字符串)。

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

  

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

答案 3 :(得分:0)

您应该使用Terms Query

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

答案 4 :(得分:0)

对于那些在2020年看到此问题的人来说,您可能会注意到在2020年已弃用了公认的答案,但是使用terms_setminimum_should_match_script组合也有类似的方法。

请在SO线程中查看详细答案here