Spring Data ElasticsearchRepository使用@Query实现动态多条件查询咨询
报错原因
你当前的写法报错是因为Spring Data Elasticsearch处理@Query注解的参数时,会自动对传入的字符串做JSON转义处理,你传入的查询片段里的双引号都会被自动加上转义符,直接拼接会破坏原有查询语句的JSON结构,所以这种硬拼接部分查询片段的方案本身不可行。
可选实现方案
@Query不是唯一的可选方案,针对你这种字段不固定、需要动态追加查询条件的场景,更推荐以下实现方式:
方案1:使用NativeSearchQuery动态构建查询(最推荐)
直接通过ElasticsearchRestTemplate执行动态构建的查询,可以根据实际存在的字段任意追加match子句,适配性最高:
import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import javax.annotation.Resource; import java.util.List; import java.util.Map; public class ActivityEsService { @Resource private ElasticsearchRestTemplate elasticsearchRestTemplate; public List<Activity> findByDynamicConditions(String resource, Map<String, Object> additionalMatchConditions) { // 初始化bool查询 BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); // 加入固定的_resource匹配条件 boolQuery.must(QueryBuilders.matchQuery("_resource", resource)); // 动态追加其他匹配条件 additionalMatchConditions.forEach((field, value) -> { boolQuery.must(QueryBuilders.matchQuery(field, value)); }); // 构建查询对象 NativeSearchQuery query = new NativeSearchQueryBuilder() .withQuery(boolQuery) .build(); // 执行查询返回结果 return elasticsearchRestTemplate.search(query, Activity.class) .stream().map(hit -> hit.getContent()).toList(); } }
调用示例:
// 需要追加的查询条件直接放入Map即可,支持任意数量、任意字段 Map<String, Object> addConditions = Map.of("_method", "GET", "_status", 200); List<Activity> result = activityEsService.findByDynamicConditions("/test/api", addConditions);
方案2:使用Criteria API动态拼接(适合简单查询场景)
如果不想直接操作ES原生查询构建器,也可以用Spring Data Elasticsearch封装的Criteria API实现动态拼接:
import org.springframework.data.elasticsearch.core.query.Criteria; import org.springframework.data.elasticsearch.core.query.CriteriaQuery; public List<Activity> findByCriteriaConditions(String resource, Map<String, Object> additionalMatchConditions) { Criteria criteria = Criteria.where("_resource").is(resource); additionalMatchConditions.forEach((field, value) -> { criteria.and(Criteria.where(field).is(value)); }); CriteriaQuery query = new CriteriaQuery(criteria); return elasticsearchRestTemplate.search(query, Activity.class) .stream().map(hit -> hit.getContent()).toList(); }
方案3:强制使用@Query的实现方式
如果一定要用@Query注解实现,可以把完整的查询JSON作为参数传入,避免部分拼接产生的转义问题:
@Query("?0") List<Activity> findByFullQuery(String fullQueryJson);
调用时自行拼接生成完整的合法bool查询JSON字符串即可,该方式需要自己保证JSON格式正确,灵活度低,不推荐使用。
总结
针对字段不固定的动态查询场景,优先选择动态构建NativeSearchQuery的方案,灵活度最高,也不会出现JSON转义异常问题。
内容的提问来源于stack exchange,提问作者Mauricio
相关产品推荐
相关产品推荐

