我想找到给定起始节点的所有路径
MATCH path=(n)-[rels*1..10]-(m)
在路径入口上具有以下2个条件:
- 如果路径中后续节点之间的关系具有属性PROP='true',则为true
- 如果
type(relationship)=SENDS
,则如果关系的方向是传出的(从路径中的一个路径节点到下一个节点),则为true
另一种说法是,除非关系名称为SENDS-,否则方向无关紧要
我可以用WHERE ALL (r IN rels WHERE r.PROP='true')
做条件1,但我不知道如何做条件2。
我能想到的在不在匹配模式中声明方向的情况下过滤关系方向的唯一方法是将路径中每个关系的起始节点与路径中nodes()
集合对应索引处的节点进行比较。为此,您需要路径中的关系和节点集合、索引计数器和一些等效于ALL()
的布尔求值。一种方法是将REDUCE
与累加器的集合一起使用,这样就可以累积索引并同时为路径维护true/false值。这里有一个例子,累加器从[0,1]
开始,其中0
是用于测试startNode(r)
等于节点集合中相应索引处的节点的索引(即,它是一个传出关系),而1
表示true
,这表示路径尚未满足您的条件。对于每个关系,索引值都会递增,如果满足条件,CASE/WHEN
子句会将"boolean"与1相乘,如果不满足条件,则将其与0相乘。路径的求值就是REDUCE
返回的集合中第二个值的求值——如果为1,则为yay,如果为0,则为boo。
MATCH path = (n)-[*1..10]-(m)
WITH path, nodes(path) as ns, relationships(path) as rs
WHERE REDUCE(acc = [0,1], r IN rs |
[acc[0]+1, CASE WHEN
r.PROP='true' AND
(type(r) <> "SENDS" OR startNode(r) = ns[acc[0]]) THEN acc[1]*1 ELSE acc[1]*0 END]
)[1] = 1
RETURN path
或者这是更可读的
WHERE REDUCE(acc = [0,1], r IN rs |
CASE WHEN
r.PROP=true AND
(type(r) <> "SENDS" OR startNode(r) = ns[acc[0]])
THEN [acc[0]+1, acc[1]*1]
ELSE [acc[0]+1, acc[1]*0]
END
)[1] = 1
这是一个控制台:http://console.neo4j.org/?id=v3kgz9
为了完整起见,我使用jjaderberg正确解决方案和一个条件来回答这个问题,以修复起始节点并确保不包括零长度路径
MATCH p = (n)-[*1..10]-(m)
WHERE ALL(n in nodes(p) WHERE 1=length(filter(m in nodes(p) WHERE m=n)))
AND (id(n)=1)
WITH p, nodes(p) as ns, relationships(p) as rs
WHERE REDUCE(acc = [0,1], r IN rs | [acc[0]+1,
CASE WHEN r.PROP='true' AND (type(r) <> "SEND" OR startNode(r) = ns[acc[0]])
THEN acc[1]*1
ELSE acc[1]*0
END])[1] = 1
RETURN nodes(p);
或者我的替代答案基于jjaderbags答案,但不使用累加器,但稍慢
MATCH p=(n)-[rels*1..10]-(m)
WHERE ALL(n in nodes(p) WHERE 1=length(filter(m in nodes(p) WHERE m=n)))
AND( ALL (r IN rels WHERE r.PROP='true')
AND id(n)=1)
WITH p, range(0,length(p)-1) AS idx, nodes(p) as ns, relationships(p) as rs
WHERE ALL (i in idx WHERE
CASE type(rs[i])='SEND'
WHEN TRUE THEN startnode(rs[i])=ns[i]
ELSE TRUE
END)
RETURN nodes(p);