我有一个非常简单的图,它有5个节点(名为n1-n5)、1个节点类型(:node)和2个关系类型(:r1,:r2)。节点和关系安排如下(对ascii艺术表示歉意):
(n1)-[:r1]->(n2)-[:r1]->(n3)
(n1)-[:r2]->(n4)-[:r2]->(n3)
(n1)-[:r1]->(n5)-[:r2]->(n3)
我有一个使用可变长度路径的查询。我希望能够通过在WHERE子句中描述一个特定的模式来限制返回的路径:
MATCH p = (n:Node {name: 'n1'})-[*..2]->()
WHERE (n)-[:r1]->()-[:r1]->()
RETURN p
问题是响应返回所有可能的路径。我的问题;在查询中指定可变长度路径时,是否可以过滤返回的路径?
如果所有关系或节点都必须遵守同一谓词,这很容易。路径需要一个变量,并且需要在WHERE子句中使用all()
(或none()
)为路径中的所有关系或节点应用谓词:
MATCH p = (n:Node {name: 'n1'})-[*..2]->()
WHERE all(rel in relationships(p) WHERE type(rel) = 'r1')
RETURN p
也就是说,当你只想让var长度路径中的所有关系都是同一类型(或者如果你想要多个类型)时,最好在模式本身中完成:
MATCH p = (n:Node {name: 'n1'})-[:r1*..2]->()
RETURN p
对于更复杂的情况,例如多个关系类型(这些类型在路径中的顺序很重要),或者在路径中重复类型序列或节点标签,则需要其他方法。APOC路径扩展器可能会有所帮助。
编辑
你在评论中提到,你的案例涉及不同长度的关系序列。虽然APOC路径扩展器可能会有所帮助,但有一些限制:
路径扩展器目前对节点标签和关系类型进行操作,但对属性不进行操作,因此,如果您的扩展依赖于属性上的谓词,则路径扩展器将无法在扩展过程中为您处理此问题,这必须通过在扩展后过滤路径扩展器结果来完成。
对路径扩展器的关系序列支持是有限制的。我们可以定义任何长度的序列,并且可以在序列的每一步接受多个关系类型,但我们目前不支持发散序列((r1然后r2然后r3)或(r2然后r5然后r6))。
如果我们想做一个r1(传入)、r2(传出)、r3或r4(r3在任一方向,r4传出)的三步序列,重复该序列多达3次,我们可以这样做:
MATCH (n:Node {name: 'n1'})
CALL apoc.path.expandConfig(n, {relationshipFilter:'<r1, r2>, r3 | r4>', minLevel:1, maxLevel:9) YIELD path
RETURN path
请注意,我们可以在过滤器中为每个关系提供不同的方向,或者如果我们不关心方向,则完全省略箭头。
标签过滤更为复杂,但到目前为止,我在示例中没有看到任何必要这样做。
您的查询返回所有路径,因为您的WHERE子句(Filter运算符)在VarLengthExpand运算符之前应用:
+-----------------------+----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+|运算符|估计行数|行数|数据库命中数|页面缓存命中数|页缓存未命中数|网页缓存命中率|变量|其他|+-----------------------+----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+|+生成结果|0|4|0|0|0.0000|anon[32],anon[41],n,p||||+----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+|+投影|0|4|0|0|0.0000|p--anon[32],anon[41],n|{p:PathExpression(NodePathStep(Variable(n),MultiRelationshipPathStep(Variable(),OUTGOING,NilPathStep))}|||+----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+|+VarLengthExpand(All)|0|4|7|0|0.0000|anon[32],anon[41]--n|(n)-[:*.2]->()|||+----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+|+筛选器|0|1|6|0|0|0.0000|n|n.name={AUTOSTRING0};GetDegree(变量(n),Some(RelTypeName(KNOWS)),OUTGOING)>0|||+----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+|+NodeByLabelScan |4|4|5|0|0|0.0000|n|:Crew|+-----------------------+----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+
这应该会让你开始:
MATCH p = (n:Node {name: 'n1'})-[*..2]->()
WITH n, relationships(p)[0] as rel0, relationships(p)[1] as rel1, p
MATCH (n)-[rel0:r1]->()-[rel1:r1]->()
RETURN p