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

Oli*_*ier 56 elasticsearch nest

我有一套像

{
    tags:['a','b','c']
    // ... a bunch properties
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

sla*_*wek 55

还有一些术语查询,可以为您节省一些工作.这里来自docs的例子:

{
  "terms" : {
      "tags" : [ "blue", "pill" ],
      "minimum_should_match" : 1
  }
}
Run Code Online (Sandbox Code Playgroud)

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

还有一个相应的术语过滤器.

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

{
  "filtered": {
    "query": {
      "match": { "title": "hello world" }
    },
    "filter": {
      "terms": {
        "tags": ["c", "d"]
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 不推荐使用`minimum_should_match`并且会失败. (9认同)

Nic*_*zny 46

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

您可能想要一个Bool查询(或者更可能是与另一个查询一起使用Filter)和一个should子句.

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

来自文档:

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

以下是Bool查询可能孤立的示例:

{
  "bool": {
    "should": [
      { "term": { "tag": "c" }},
      { "term": { "tag": "d" }}
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

这是另一个Bool查询作为更通用的过滤查询中的过滤器的示例:

{
  "filtered": {
    "query": {
      "match": { "title": "hello world" }
    },
    "filter": {
      "bool": {
        "should": [
          { "term": { "tag": "c" }},
          { "term": { "tag": "d" }}
        ]
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Elasticsearch博客:所有关于Elasticsearch过滤器位集

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

现在,完成所有这些后,terms查询就是上述所有内容的DRYer版本.它对于引擎下的查询类型做了正确的事情,它的行为与使用选项的bool+ 相同,总体来说有点简洁.shouldminimum_should_match

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

{
  "filtered": {
    "query": {
      "match": { "title": "hello world" }
    },
    "filter": {
      "terms": {
        "tag": [ "c", "d" ],
        "minimum_should_match": 1
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • minimum_should_match现已弃用 (4认同)

Abd*_*jid 9

对于那些在 2020 年关注此问题的人,您可能会注意到已接受的答案在 2020 年已被弃用,但有一种类似的方法可以使用terms_setminimum_should_match_script组合。

请参阅SO 线程中的详细答案


mdm*_*jsh 6

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

一个term查询可以用来查找反向索引指定的确切期限:

{
  "query": {
   "term" : { "tags" : "a" }
} 
Run Code Online (Sandbox Code Playgroud)

从文档https://www.elastic.co/guide/zh/elasticsearch/reference/current/query-dsl-term-query.html

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

{
  "query": {
   "terms" : { "tags" : ["a", "c"]}
} 
Run Code Online (Sandbox Code Playgroud)

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

需要注意的一个陷阱(这让我感到困惑)-如何定义文档也有所不同。如果您要搜索的字段已被索引为text类型,则Elasticsearch将执行全文搜索(即使用analyzed字符串)。

如果您已将该字段编入索引,keyword则将执行使用“未分析”字符串的关键字搜索。这可能有一个巨大的实际影响为分析字符串进行预处理(小写,标点符号下降等)见(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