【问题标题】:Filter items which array contains any of given values过滤数组包含任何给定值的项目
【发布时间】:2015-03-16 02:25:31
【问题描述】:

我有一组类似的文档

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

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

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

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

【问题讨论】:

    标签: elasticsearch nest


    【解决方案1】:

    弹性搜索 2.0.1:

    还有terms query 可以为您节省一些工作。这里是来自文档的示例:

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

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

    还有一个对应的terms filter

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

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

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

    【讨论】:

    • 我无法让它工作。你介意看看这里stackoverflow.com/questions/32252789/…
    • minimum_should_match 已弃用并将失败。
    • @AinTohvri 实际上在 elasticsearch 2.0.1 minimum_should_match 中仍然有效,官方文档并未将其标记为已弃用。
    • 如果我不想要标签中的特定关键字,如何工作。假设我有 5 个关键字 a、b、c、d、e.. 我不想在标签中使用 c 关键字。查询会是什么?
    • 有点取决于您使用的弹性搜索版本。但在大多数情况下,您只需要否定条件。例如,如果您在boolean 查询的mustNot 子句中使用完全相同的terms 条件,它将搜索所有没有任何标签的文档。
    【解决方案2】:

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

    您可能需要 Bool Query(或者更可能是 Filter 旁边的另一个查询),并带有 should 子句。

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

    来自文档:

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

    以下是 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 而不是 And/Or/Not(反之亦然)的好例子。

    Elasticsearch 博客:All About Elasticsearch Filter Bitsets

    使用重构查询更新...

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

    这是最后一个查询的重构:

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

    【讨论】:

    • minimum_should_match 现已弃用
    • minimum_should_match 不会解决问题,如果您还按另一个数组过滤,您需要正常的“或”行为。
    【解决方案3】:

    虽然这是一个老问题,但我最近自己遇到了这个问题,这里的一些答案现在已被弃用(正如 cmets 指出的那样)。因此,为了其他可能在这里偶然发现的人的利益:

    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,则使用“未分析”字符串执行关键字搜索。这可能会产生巨大的实际影响,因为已分析的字符串是经过预处理的(小写、标点符号删除等)请参阅 (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)

    【讨论】:

      【解决方案4】:

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

      详细答案请看SO线程here

      【讨论】:

        【解决方案5】:

        你应该使用Terms Query

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

        【讨论】:

          猜你喜欢
          • 2020-02-13
          • 2020-01-02
          • 2017-11-02
          • 1970-01-01
          • 2012-02-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-09-01
          相关资源
          最近更新 更多