ES Bool查询转Java代码时返回全量数据的问题排查与修复建议
问题分析与修复方案
问题背景
你尝试将以下可在控制台正常运行的ES查询转换为Java代码:
原ES查询DSL:
{"query": {"bool": {"must": [{"match": {"ID.keyword": "1234457654"}}, {"bool": {"should": [{"match": {"stepName.keyword": "STEP1"}}, {"match": {"stepName.keyword": "STEP2"}}]}}]}}}
编写的Java代码:
QueryBuilder qb = QueryBuilders.boolQuery() .must(QueryBuilders.matchQuery("ID.keyword", transformedDataDTO.getID()).operator(Operator.AND)) .should(QueryBuilders.matchQuery("stepName.keyword", transformedDataDTO.getStepName())) .should(QueryBuilders.matchQuery("stepName.keyword", MigrationStatusEnum.getPreviousData(transformedDataDTO.getStepName())));
出现的问题:代码未返回匹配STEP1或STEP2的数据,反而返回了所有符合ID条件的数据。
问题原因
原DSL中,stepName的两个匹配条件是嵌套在外层bool的must中的独立bool查询里的。这个内层bool仅包含should条件,Elasticsearch默认要求这类bool查询至少满足一个should条件(minimum_should_match=1)。
而你的Java代码直接将两个should放在了外层bool查询下。当外层bool同时存在must和should时,Elasticsearch默认将should视为可选条件(minimum_should_match=0)——只要满足must的ID匹配条件,无论stepName是否匹配都会返回文档,这就是为什么会返回所有ID匹配的数据。
修复方案
将两个stepName的should查询嵌套到一个新的bool查询中,再将这个bool查询作为外层bool的第二个must条件,和原DSL结构保持一致:
方案1:拆分变量写法
// 构建内层bool查询,包含stepName的两个should条件 QueryBuilder stepNameSubQuery = QueryBuilders.boolQuery() .should(QueryBuilders.matchQuery("stepName.keyword", transformedDataDTO.getStepName())) .should(QueryBuilders.matchQuery("stepName.keyword", MigrationStatusEnum.getPreviousData(transformedDataDTO.getStepName()))); // 构建外层bool查询,同时满足ID匹配和内层stepName条件 QueryBuilder qb = QueryBuilders.boolQuery() .must(QueryBuilders.matchQuery("ID.keyword", transformedDataDTO.getID()).operator(Operator.AND)) .must(stepNameSubQuery);
方案2:链式调用写法
QueryBuilder qb = QueryBuilders.boolQuery() .must(QueryBuilders.matchQuery("ID.keyword", transformedDataDTO.getID()).operator(Operator.AND)) .must(QueryBuilders.boolQuery() .should(QueryBuilders.matchQuery("stepName.keyword", transformedDataDTO.getStepName())) .should(QueryBuilders.matchQuery("stepName.keyword", MigrationStatusEnum.getPreviousData(transformedDataDTO.getStepName()))));
修改后,内层bool查询会强制要求至少匹配一个stepName条件,外层bool要求同时满足ID匹配和内层条件,逻辑与原DSL完全一致,只会返回ID匹配且stepName为目标值之一的文档。
内容的提问来源于stack exchange,提问作者rohit saraf
相关产品推荐
相关产品推荐

