将可用Elasticsearch查询转Java实现时遇编译错误求解决方案
解决Spring Data Elasticsearch @Query注解编译错误及正确实现
问题场景
有一段可在Kibana正常运行的Elasticsearch查询,尝试通过Spring Data Elasticsearch Repository的@Query注解转换为Java代码时,编译阶段报错:
Error: Reason: No property searchLocationOnLevel found for type LocationSearch!; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property searchLocationOnLevel found for type LocationSearch!
原Elasticsearch查询语句
GET dev_skp_location/_search { "query": { "bool": { "must": [ { "regexp": { "name": ".*pur*" } }, { "nested": { "path": "locationType", "query": { "bool": { "must": [ { "match": { "locationType.level": "1" } } ] } }, "score_mode": "avg" } } ] } } }
用户尝试的错误代码
@Query("{\n" + " \"bool\":{\n" + " \"must\":[\n" + " {\n" + " \"regexp\": { \"name\": \"\\.*pur\\*\"}\n" + " },\n" + " {\n" + " \"nested\": {\n" + " \"path\": \"locationType\",\n" + " \"query\": {\n" + " \"bool\": {\n" + " \"must\": [\n" + " { \n" + " \"match\": { \"locationType.level\": \"1\" } \n" + " \n" + " }]\n" + " }\n" + " },\n" + " \"score_mode\": \"avg\"\n" + " }\n" + " }\n" + " ]\n" + " }\n" + " }") Page<LocationSearch> searchLocationOnLevel(String loc, String level, Pageable pageable);
错误原因分析
- Repository父接口错误:如果Repository继承的是
JpaRepository而非ElasticsearchRepository,Spring会按JPA规则解析方法名,导致找不到对应属性的错误。 - 参数未占位:方法定义了
loc和level参数,但查询语句中硬编码了值,未使用参数占位符。 - JSON语法错误:原查询的JSON存在括号闭合问题,且Java字符串中的转义字符处理不当。
- Regexp写法问题:原ES查询的
.*pur*语义是匹配任意字符+pu后接0个或多个r,若要匹配包含pur的字符串,应改为.*pur.*。
正确实现方式
1. 确保Repository继承正确的父接口
Repository必须继承ElasticsearchRepository,而非JPA相关接口:
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 LocationSearchRepository extends ElasticsearchRepository<LocationSearch, String> { // 方法定义 }
2. 修正@Query语句(位置参数版)
使用?0、?1对应方法的第1、第2个参数,同时修正JSON语法和转义:
@Query("{\n" + " \"query\": {\n" + " \"bool\": {\n" + " \"must\": [\n" + " {\n" + " \"regexp\": { \"name\": \"?0\" }\n" + " },\n" + " {\n" + " \"nested\": {\n" + " \"path\": \"locationType\",\n" + " \"query\": {\n" + " \"bool\": {\n" + " \"must\": [\n" + " {\n" + " \"match\": { \"locationType.level\": \"?1\" }\n" + " }\n" + " ]\n" + " }\n" + " },\n" + " \"score_mode\": \"avg\"\n" + " }\n" + " }\n" + " ]\n" + " }\n" + " }\n" + "}") Page<LocationSearch> searchLocationOnLevel(String locPattern, String level, Pageable pageable);
3. 修正@Query语句(命名参数版)
若使用命名参数,需配合@Param注解,可读性更强:
import org.springframework.data.repository.query.Param; // ... @Query("{\n" + " \"query\": {\n" + " \"bool\": {\n" + " \"must\": [\n" + " {\n" + " \"regexp\": { \"name\": \":locPattern\" }\n" + " },\n" + " {\n" + " \"nested\": {\n" + " \"path\": \"locationType\",\n" + " \"query\": {\n" + " \"bool\": {\n" + " \"must\": [\n" + " {\n" + " \"match\": { \"locationType.level\": \":level\" }\n" + " }\n" + " ]\n" + " }\n" + " },\n" + " \"score_mode\": \"avg\"\n" + " }\n" + " }\n" + " ]\n" + " }\n" + " }\n" + "}") Page<LocationSearch> searchLocationOnLevel(@Param("locPattern") String locPattern, @Param("level") String level, Pageable pageable);
4. 确保实体类映射正确
LocationSearch实体类需正确映射ES索引,嵌套字段locationType需标注@Nested注解:
import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; import org.springframework.data.elasticsearch.annotations.Nested; @Document(indexName = "dev_skp_location") public class LocationSearch { private String id; @Field(type = FieldType.Text) private String name; @Nested private LocationType locationType; // getter、setter方法 } class LocationType { @Field(type = FieldType.Keyword) private String level; // 其他字段及getter、setter }
5. 方法调用示例
若要匹配包含pur的名称和level为1的记录,调用时传入正确的正则表达式:
Page<LocationSearch> result = locationSearchRepository.searchLocationOnLevel(".*pur.*", "1", PageRequest.of(0, 10));
内容的提问来源于stack exchange,提问作者Ajay Kushwaha
相关产品推荐
相关产品推荐

