为了账号安全,请及时绑定邮箱和手机立即绑定

ElasticSearch 通过数组字段搜索作为独占搜索

ElasticSearch 通过数组字段搜索作为独占搜索

qq_笑_17 2023-03-09 14:02:47
我在 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 回答

?
慕容3067478

TA贡献1773条经验 获得超3个赞

重新索引解决方案:

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

}

在爪哇,


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);


查看完整回答
反对 回复 2023-03-09
  • 1 回答
  • 0 关注
  • 99 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信