如何在ElasticsearchRepository中实现Optional字段及列表包含匹配查询
解决方案
你可以通过两种常用的方式实现这个动态查询需求:
方式一:使用ElasticsearchOperations手动构建布尔查询(最灵活,适配动态可选参数)
这种方式完全可控,适合参数动态变化的场景,首先需要扩展自定义Repository实现:
public interface SampleRepository extends ElasticsearchRepository<Sample, String>, CustomSampleRepository { } // 自定义查询接口 public interface CustomSampleRepository { List<Sample> getAll(String n_id, Optional<String> b_ref, Optional<String> r_ref, List<Status> statuses); }
实现自定义接口逻辑:
public class CustomSampleRepositoryImpl implements CustomSampleRepository { private final ElasticsearchOperations elasticsearchOperations; // 构造注入ElasticsearchOperations public CustomSampleRepositoryImpl(ElasticsearchOperations elasticsearchOperations) { this.elasticsearchOperations = elasticsearchOperations; } @Override public List<Sample> getAll(String n_id, Optional<String> b_ref, Optional<String> r_ref, List<Status> statuses) { BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); // 必填n_id参数精确匹配 boolQuery.must(QueryBuilders.termQuery("n_id", n_id)); // 可选参数存在时才添加查询条件 b_ref.ifPresent(val -> boolQuery.must(QueryBuilders.termQuery("b_ref", val))); r_ref.ifPresent(val -> boolQuery.must(QueryBuilders.termQuery("r_ref", val))); // Status列表包含匹配,用termsQuery // 若枚举在ES中存的是序数而非名称,把Enum::name替换为Enum::ordinal即可 boolQuery.must(QueryBuilders.termsQuery("status", statuses.stream().map(Enum::name).toList())); NativeSearchQuery query = new NativeSearchQueryBuilder() .withQuery(boolQuery) .build(); SearchHits<Sample> searchHits = elasticsearchOperations.search(query, Sample.class); return searchHits.stream().map(SearchHit::getContent).toList(); } }
方式二:使用@Query注解+SpEL适配可选参数
如果不想写自定义实现类,也可以通过原生DSL配合SpEL表达式实现动态逻辑,直接在Repository接口中定义方法即可:
public interface SampleRepository extends ElasticsearchRepository<Sample, String> { @Query(""" { "bool": { "must": [ {"term": {"n_id": "?0"}}, #if(?1.isPresent()) {"term": {"b_ref": "?1.get()"}}, #end #if(?2.isPresent()) {"term": {"r_ref": "?2.get()"}}, #end {"terms": {"status": [?3.![name()]]}} ] } } """) List<Sample> getAll(String n_id, Optional<String> b_ref, Optional<String> r_ref, List<Status> statuses); }
注意事项:
- 语法
?3.![name()]是SpEL集合投影写法,会自动把枚举列表转换为枚举名的集合,若存的是序数替换为?3.![ordinal()]即可 - 该写法需要Spring Data Elasticsearch 4.0及以上版本支持
- 如果你的字段是text类型,term查询无法命中,需要替换为match查询
内容的提问来源于stack exchange,提问作者H Athukorala
相关产品推荐
相关产品推荐

