如何查询ElasticSearch以查找至少一个不在数组中的术语的对象

时间:2019-02-07 19:14:15

标签: elasticsearch

在这个问题上,假设我们有一个

这样的映射
{
  tags: { type: 'string' }, // array of strings input
  name: { type: 'string' }
}

给标签一个数组。假设我们随后将以下文档编入索引:

[{
  tags: ['a', 'b', 'c'],
  name: 'Alpha'
}, {
  tags: ['b', 'c', 'd'],
  name: 'Beta'
}, {
  tags: ['c', 'd', 'e'],
  name: 'Gamma'
}, {
  tags: ['b', 'c', 'd', 'e'],
  name: 'Delta'
}, {
  tags: [],
  name: 'Eta'
}]

有没有一种结构化查询的方法,使得它可以找到给定数组中具有至少一个标签 not 的所有文档?例如,给出['b','c','d'] ,它应返回名为 Alpha 的对象(不包含'a'在给定数组中), Gamma (在给定数组中没有'e')和 Delta (也有'e'不在给定数组中。)

2 个答案:

答案 0 :(得分:0)

如果您可以将“输入数组”的概念更改为布尔查询-这将起作用

 {
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "must_not": {
              "term": {
                "tags": "b"
              }
            }
          }
        },
        {
          "bool": {
            "must_not": {
              "term": {
                "tags": "c"
              }
            }
          }
        },
        {
          "bool": {
            "must_not": {
              "term": {
                "tags": "d"
              }
            }
          }
        }
      ],
      "must" : { "wildcard" : {"tags": "*"}},
      "minimum_should_match": 1
    }
  }
}

答案 1 :(得分:0)

恐怕这是不可能的,因为Elasticsearch将数据存储在inverted indexes中,该数据结构可以回答“哪些文档具有特定标记”而不是“哪些文档没有其他标记”的问题“。

您可以尝试几种方法。

明确指定匹配tags

如果事先知道所有可能的tags的集合,并且字段的基数(==唯一标记的数量)不太高(例如,小于1000),则可以这样做。 / p>

如果可能值的集合未知,则可以通过terms聚合来获取。在这种情况下,您将必须执行2个查询,而不是1个。

在您所提问题的示例中,这意味着要索取在["a", "e"]中带有标签的所有文档。

使用script查询

script查询本质上是full-scan查询,并允许用户根据需要定义匹配/不匹配条件。主要缺点是性能,因为Elasticsearch将无法使用其任何反向索引,因此本质上将必须扫描所有文档。

此选项在某些情况下可能会有用,例如进行分析或证明某些假设。

重塑数据

由于通用方法不可行,因此可能会证明您的业务案例实际上不是通用的。查看您需要执行的查询,并针对用例进行优化。

例如,如果搜索“任何 b,c,d 的标签”是重复的用例,则定义一个类似标志的字段"contains_not_b_c_d"并预先计算。

我真的希望我能对此做出更积极的评价,但这种用例并不是Elasticsearch兴旺发达的地方。


希望有帮助!