ElasticSearch 通过数组字段搜索作为独占搜索
ElasticSearch search through an array field as exclusive search
我在 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
此 return 文档 1 和 2,因为文档 2 也包含 TSX。但是,我希望它 return 仅 文档 1 而数组中没有其他文件。
我该如何完成?
提前致谢。
Re-index 解决办法:
我最近从 ElasticSearch 找到了这个文档:
https://www.elastic.co/guide/en/elasticsearch/guide/current/_finding_multiple_exact_values.html
TermQuery 和 TermsQuery 或 ElasticSearch 通常都使用 'must contain' 而不是 'must equals to' 因为它的倒排索引。
根据他们的说法,最好的解决方案是:
If you do want that behavior—entire field equality—the best way to accomplish it involves indexing a secondary field. In this field, you index the number of values that your field contains. Using our two previous documents. Once you have the count information indexed, you can construct a constant_score that enforces the appropriate number of terms. https://www.elastic.co/guide/en/elasticsearch/guide/current/_finding_multiple_exact_values.html#_equals_exactly
以下步骤:
- 在名为 exgroups_count 的索引中添加额外的映射。
- 使用logstash统计exgroups数组长度,放入exgroups_count字段
- 保存索引。
另一个没有Re-index的解决方案:
添加和 re-indexing 整个事情有一些限制。一旦您的索引增长,向索引添加字段和计算计数将是非常具有侵入性的 - 使其操作非常密集 - 更不用说您必须保存和维护您的映射。
我找到了一个不需要 re-index 的解决方案。查看 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);
我在 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
此 return 文档 1 和 2,因为文档 2 也包含 TSX。但是,我希望它 return 仅 文档 1 而数组中没有其他文件。
我该如何完成?
提前致谢。
Re-index 解决办法:
我最近从 ElasticSearch 找到了这个文档: https://www.elastic.co/guide/en/elasticsearch/guide/current/_finding_multiple_exact_values.html
TermQuery 和 TermsQuery 或 ElasticSearch 通常都使用 'must contain' 而不是 'must equals to' 因为它的倒排索引。
根据他们的说法,最好的解决方案是:
If you do want that behavior—entire field equality—the best way to accomplish it involves indexing a secondary field. In this field, you index the number of values that your field contains. Using our two previous documents. Once you have the count information indexed, you can construct a constant_score that enforces the appropriate number of terms. https://www.elastic.co/guide/en/elasticsearch/guide/current/_finding_multiple_exact_values.html#_equals_exactly
以下步骤:
- 在名为 exgroups_count 的索引中添加额外的映射。
- 使用logstash统计exgroups数组长度,放入exgroups_count字段
- 保存索引。
另一个没有Re-index的解决方案:
添加和 re-indexing 整个事情有一些限制。一旦您的索引增长,向索引添加字段和计算计数将是非常具有侵入性的 - 使其操作非常密集 - 更不用说您必须保存和维护您的映射。
我找到了一个不需要 re-index 的解决方案。查看 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);