OrientDB MATCH查询返回不存在路径问题求助
哈哈,这个问题我之前也碰到过!你的推测完全正确,问题确实出在bothE()和bothV()的遍历逻辑,再加上起始节点John Smith本身就满足终点的lastName过滤条件,才导致了这条莫名其妙的“自连接”路径。
问题根源拆解
当你使用bothE()时,会取出当前节点的所有入边和出边;紧接着的bothV()会取出每条边的两个端点。对于那条连接John和Dan的PhoneCall边来说,bothV()会同时返回John和Dan两个节点。而因为John的lastName也是Smith,刚好符合E0的过滤条件,所以这条边就被错误匹配成了「John --phoneCallX-- John」的路径——哪怕这条边根本不是自环边,遍历逻辑还是把起始节点当成了合法的终点。
几种可行的解决方案
1. 明确边的遍历方向(优先推荐)
如果你的PhoneCall边是有向的(比如从主叫方指向被叫方),直接用outE()和inV()(或者根据实际方向反过来)替代bothE()和bothV(),这样只会沿着单一方向遍历,彻底避免回到起始节点:
MATCH {class:person, as:E1, where:(firstName IN ['John'])}.outE(){class:phoneCall, as:R0}.inV(){class:person, as:E0, where:(lastName IN ['Smith'])} RETURN $paths
要是边是无向的,也可以用outE()+inV()或者inE()+outV()的组合,效果一样能避免遍历回自身。
2. 在终点过滤中排除起始节点
如果不想改变遍历方向,也可以在E0的where条件里加个判断,强制终点不能是起始节点本身:
MATCH {class:person, as:E1, where:(firstName IN ['John'])}.bothE(){class:phoneCall, as:R0}.bothV(){class:person, as:E0, where:(lastName IN ['Smith'] AND @rid != E1.@rid)} RETURN $paths
通过@rid != E1.@rid来过滤掉和起始节点ID相同的节点,就能排除那条虚假路径。
3. 使用更直观的MATCH路径语法
OrientDB支持类似Cypher的路径语法,写起来更直观,同时加上判断排除自连接:
MATCH (E1:person {firstName: 'John'})-[R0:phoneCall]-(E0:person {lastName: 'Smith'}) WHERE E1 != E0 RETURN $paths
这种写法逻辑更清晰,WHERE E1 != E0直接确保起始节点和终点不是同一个,从根源上避免虚假路径。
总结
核心问题就是bothV()会返回边的两个端点,而你的起始节点刚好满足终点的过滤规则,才产生了这条不存在的路径。上面三种方法都能解决问题,优先推荐第一种明确方向的写法,逻辑最严谨,性能也更好。
内容的提问来源于stack exchange,提问作者Tami Wert

