Elasticsearch 匹配完整的术语数组

Elasticsearch match complete array of terms

我需要用 elasticsearch 匹配完整的词组。 只应返回具有包含相同元素的数组的文档。 文档数组中不应有更多元素或元素子集。 元素的顺序无关紧要。

示例:

 filter:
   id: ["a", "b"]

 documents:  
   id: ["a", "b"] -> match  
   id: ["b", "a"] -> match  
   id: ["a"] -> no match  
   id: ["a", "b", "c"] -> no match  

最终我想使用 Java 高级 REST 客户端来实现查询,尽管 elasticsearch dsl 的示例也可以。

虽然这似乎不受本地支持,但您可以继续使用脚本过滤器来实现此行为,如下所示:

GET your_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "script": {
            "script": "doc['tags'].values.length == 2"
          }
        },
        {
          "term": {
            "tags": {
              "value": "a"
            }
          }
        },
        {
          "term": {
            "tags": {
              "value": "b"
            }
          }
        }
      ]
    }
  }
}

脚本过滤器通过数组大小限制搜索结果,而术语过滤器指定该数组的值。确保在标签 字段 上启用 fielddata 以便在其上执行脚本。

我想提出一些建议,一旦您的要求发生变化(例如,假设您有一个包含六个项目的数组要匹配),将阻止您维护一长串 "must" 条件。我将依赖脚本查询,它可能看起来设计过度,但可以很容易地从中创建搜索模板 (https://www.elastic.co/guide/en/elasticsearch/reference/7.5/search-template.html)。

{
"query": {
    "bool": {
      "filter": {
        "script": {
          "script": {
            "source": """
              def ids = new ArrayList(doc['id.keyword']);
              def param = new ArrayList(params.terms);
              def isSameSize = ids.size() == param.size();
              def isSameContent = ids.containsAll(param);
              return isSameSize && isSameContent
            """,
            "lang": "painless",
            "params": {
              "terms": [ "a", "b" ]
            }
          }
        }
      }
    }
  }
}

这样,您唯一需要更改的是 terms 参数的值。