【问题标题】:ElasticSearch search through an array field as exclusive searchElasticSearch 通过数组字段搜索作为排他搜索
【发布时间】:2019-11-16 10:17:41
【问题描述】:

我在 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、TermQueryBuilder 无济于事。根据 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。但是,我希望它返回 only 文档 1,而不返回数组中的其他内容。

我该如何做到这一点?

提前致谢。

【问题讨论】:

    标签: java elasticsearch elastic-stack


    【解决方案1】:

    重新索引解决方案:

    我最近从 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);
    

    【讨论】:

      猜你喜欢
      • 2018-08-08
      • 2021-03-10
      • 2016-09-07
      • 1970-01-01
      • 1970-01-01
      • 2018-12-28
      • 2018-10-12
      • 2018-12-22
      • 1970-01-01
      相关资源
      最近更新 更多