ElasticSearch通过数组字段进行搜索作为互斥搜索

时间:2019-07-05 20:19:00

标签: java elasticsearch elastic-stack

我确实在ElasticSearch的字段中具有关键字类型的数据数组。我想使用要搜索的互斥值来搜索此数组,即排除搜索关键字中未包含的数组值。请查看下面的详细信息。

谢谢!

我具有以下弹性搜索索引映射:

"exgroups": {
  "type": "keyword",
  "eager_global_ordinals": true
},

具有以下示例数据:

"id": 1,
"exgroups": ["TSX"]

"id": 2,
"exgroups": ["TSX", "OTC", "NSD"]

我的搜索是这样的:

{
  "bool" : {
    "filter" : {

        "term" : {
          "exgroups" : {
            "value" : "TSX"
          }
        }

    }
  }
}

我没有使用MatchQueryBuilder,TermQueryBuilder,TermsQueryBuilder。通过ElasticSearch TermQuery定义,它可以解决问题。 https://www.elastic.co/guide/en/elasticsearch/reference/6.2/query-dsl-term-query.html。但这不是,可能是因为该字段是一个数组。

通常,Term * Query的行为如下:

iterate all the documents, for each document
  check if the exgroups contains 'tsx'
  if it does, return the document

这将返回文档1和2,因为文档2也包含TSX。但是,我希望它只返回 文档1,而不返回数组中的其他任何文件。

我如何做到这一点?

谢谢。

1 个答案:

答案 0 :(得分:2)

重新索引解决方案:

我最近从ElasticSearch找到了这个文档: https://www.elastic.co/guide/en/elasticsearch/guide/current/_finding_multiple_exact_values.html

由于其倒置索引,TermQuery,TermsQuery或ElasticSearch通常都使用“必须包含”而不是“必须等于”。

根据他们的说法,最好的解决方案是:

  

如果您确实希望这种行为(整个字段相等),则最好的方法是对第二个字段进行索引。在此字段中,索引字段包含的值的数量。使用我们之前的两个文档。一旦索引了计数信息,就可以构造一个constant_score,以实施适当数量的术语。 https://www.elastic.co/guide/en/elasticsearch/guide/current/_finding_multiple_exact_values.html#_equals_exactly

以下步骤:

  1. 在名为exgroups_count的索引中添加其他映射。
  2. 使用logstash计算exgroups数组的长度并将其放入exgroups_count字段中。
  3. 保存索引。

另一种无需重新编制索引的解决方案:

添加和重新索引整个内容存在一些限制。一旦索引增长,将很麻烦地在索引中添加字段,并计算计数-使其非常耗费操作-更不用说您必须保存和维护映射。

我找到了不需要重新编制索引的解决方案。查看ScriptQueryBuilder,从理论上讲,我可以添加一个脚本过滤器,该过滤器计算数组的长度并等于1。

"filter" : {
    "script" : {
        "script" : "doc['exgroups'].values.length == 1"
    }
}

因此完整的查询现在变成这样:

"bool" : {
  "must" : [
    {
      "term" : {
        "exgroups" : {
          "value" : "TSX",
          "boost" : 1.0
        }
      }
    }
  ],
  "filter" : [
    {
      "script" : {
        "script" : {
          "source" : "doc['exgroups'].values.length == 1",
          "lang" : "painless"
        },
        "boost" : 1.0
      }
    }
  ],
  "adjust_pure_negative" : true,
  "boost" : 1.0
}

在Java中,

BoolQueryBuilder qBool = new BoolQueryBuilder();
TermQueryBuilder query = new TermQueryBuilder("exgroups", exchangeGroup.getCode());

qBool.must(query);

ScriptQueryBuilder sQuery = new ScriptQueryBuilder(new Script("doc['exgroups'].values.length == 1"));

qBool.filter(sQuery);