Spring Data Neo4j自定义Cypher正则查询无结果问题排查
问题分析与解决方案
这个问题我之前也碰到过,核心原因是Spring Data Neo4j对@Query里的参数占位符处理和你想的不一样!
问题根源
你原来的@Query写法里,把{0}和{1}直接嵌在了正则表达式的字符串字面量中,比如'/path/{0}/.*/{1}'。但Spring Data Neo4j在解析这个查询时,会把{0}转换成Cypher的参数占位符$0——问题就出在这:在Neo4j的正则表达式语法里,$0是反向引用符号(代表整个匹配的字符串),而不是用来绑定参数的占位符!
所以实际执行的Cypher查询其实是:
MATCH (n:Component) WHERE n.path =~ '/path/$0/.*/$1' RETURN n
这里的$0和$1被正则引擎当成了反向引用规则,根本没有替换成你传入的foo和baz,自然匹配不到任何结果,返回null。
解决方法
只要把参数和正则的固定部分用字符串拼接的方式组合,让SDN正确把参数值插入到正则字符串中就行,这里提供三种可行方案:
方案1:使用索引参数拼接
@Query("MATCH (n:Component) WHERE n.path =~ ('/path/' + {0} + '/.*/' + {1}) RETURN n") Component findByTenantAndName(String tenant, String name);
方案2:使用命名参数(更易读)
import org.springframework.data.neo4j.annotation.Query; import org.springframework.data.repository.query.Param; // ... @Query("MATCH (n:Component) WHERE n.path =~ ('/path/' + $tenant + '/.*/' + $name) RETURN n") Component findByTenantAndName(@Param("tenant") String tenant, @Param("name") String name);
方案3:提前构建正则字符串(灵活度更高)
如果你的正则规则可能变化,也可以在Java层先拼好完整的正则表达式,再传入查询:
@Query("MATCH (n:Component) WHERE n.path =~ $regex RETURN n") Component findByRegex(@Param("regex") String regex); // 调用时 String regex = String.format("/path/%s/.*/%s", "foo", "baz"); Component component = yourRepository.findByRegex(regex);
这样修改后,SDN会正确把参数值拼接到正则字符串里,执行的查询就和你在Neo4j控制台手动写的一模一样了,自然能匹配到/path/foo/bar/baz的节点。
内容的提问来源于stack exchange,提问作者Sebastian Wramba
相关产品推荐
相关产品推荐

