Spring Boot+JPA+Elasticsearch实现*与?通配符匹配查询
解决方案:Spring Boot 3 Elasticsearch 实现*和?通配符匹配
核心问题分析
你的?通配符失效,大概率是因为依赖Spring Data的派生查询(如findByCodeLike)时,框架对通配符的处理逻辑有限,仅支持*而未正确解析?。Elasticsearch原生支持*(匹配任意长度字符)和?(匹配单个任意字符)的通配符查询,只需调整查询实现方式即可解决。
方案1:手动构建Wildcard查询(推荐,灵活可控)
直接使用Elasticsearch的WildcardQueryBuilder构建查询,绕过Spring Data派生查询的限制,直接传递通配符参数。
代码实现(基于ElasticsearchRestTemplate)
import org.elasticsearch.index.query.QueryBuilders; import org.springframework.data.domain.PageRequest; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.SearchHit; import org.springframework.data.elasticsearch.core.SearchHits; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.stereotype.Service; import java.util.List; import java.util.stream.Collectors; @Service public class CodeService { private final ElasticsearchRestTemplate esRestTemplate; // 构造注入 public CodeService(ElasticsearchRestTemplate esRestTemplate) { this.esRestTemplate = esRestTemplate; } public List<CodeEntity> searchCodeByPattern(String pattern) { // 构建原生查询,直接使用传入的*和?通配符 var searchQuery = new NativeSearchQueryBuilder() .withQuery(QueryBuilders.wildcardQuery("code", pattern)) .withPageable(PageRequest.of(0, 100)) // 限制返回前100条 .build(); SearchHits<CodeEntity> hits = esRestTemplate.search(searchQuery, CodeEntity.class); return hits.stream() .map(SearchHit::getContent) .collect(Collectors.toList()); } }
方案2:Repository层使用@Query注解
在自定义Repository中通过原生Elasticsearch查询语句实现通配符支持,适合希望保留Repository风格的场景。
Repository代码
import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.annotations.Query; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; public interface CodeRepository extends ElasticsearchRepository<CodeEntity, String> { // 原生Wildcard查询,?0对应第一个参数 @Query("{\"wildcard\": {\"code\": {\"value\": \"?0\"}}}") Page<CodeEntity> findByCodePattern(String pattern, Pageable pageable); }
Service调用代码
import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import java.util.List; @Service public class CodeService { private final CodeRepository codeRepository; public CodeService(CodeRepository codeRepository) { this.codeRepository = codeRepository; } public List<CodeEntity> searchCodeByPattern(String pattern) { // 传入分页参数,取第0页的100条数据 return codeRepository.findByCodePattern(pattern, PageRequest.of(0, 100)).getContent(); } }
关键配置:确保字段为Keyword类型
通配符查询对字段类型敏感,如果code字段是text类型且开启了分词,查询结果会不符合预期。必须在实体类中指定code为Keyword类型:
import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; @Document(indexName = "codes") public class CodeEntity { private String id; @Field(type = FieldType.Keyword) // 必须设置为Keyword,避免分词干扰 private String code; // Getter、Setter省略 }
注意事项
- 通配符放在字符串开头(如
*AA)会导致Elasticsearch无法使用索引,查询性能大幅下降,建议业务上引导用户将通配符放在末尾。 - 如果需要更复杂的模糊匹配,也可以考虑使用
regexpQuery,但性能比wildcard更差,需谨慎使用。
内容的提问来源于stack exchange,提问作者gcbox999
相关产品推荐
相关产品推荐

