如何在可变长度Cypher查询中按模式过滤

时间:2018-10-22 12:46:14

标签: filter neo4j path variable-length

我有一个非常简单的图,其中包含5个节点(命名为n1-n5),1个节点类型(:Node)和2个关系类型(:r1,:r2)。节点和关系的安排如下(为道歉):

(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

问题是响应返回所有可能的路径。我的问题;在查询中指定可变长度路径时,是否可以过滤返回的路径?

2 个答案:

答案 0 :(得分:0)

如果所有关系或节点必须遵循相同的谓词,这很容易。您将需要一个变量作为路径,并且需要在WHERE子句中使用all()(或none())将谓词应用于路径中的所有关系或节点:

MATCH p = (n:Node {name: 'n1'})-[*..2]->()
WHERE all(rel in relationships(p) WHERE type(rel) = 'r1')
RETURN p

也就是说,当您想要使var-length路径中的所有关系具有相同的类型(或多个类型,如果您想要多个)时,最好在模式本身中完成:

MATCH p = (n:Node {name: 'n1'})-[:r1*..2]->()
RETURN p

对于更复杂的情况,例如多种关系类型(这些类型的顺序在路径中很重要),或在路径中重复类型或节点标签的序列,则需要替代方法。 APOC path expanders可能会有帮助。

编辑

您在评论中提到,您的案件涉及不同长度的关系序列。尽管APOC路径扩展器可能会有所帮助,但有一些限制:

  1. 路径扩展器当前仅在节点标签和关系类型上运行,而不在属性上运行,因此,如果您的扩展依赖于谓词上的属性,那么路径扩展器将无法在扩展过程中为您处理必须通过过滤路径扩展器的结果来完成。

  2. 对路径扩展器的关系序列支持存在限制。我们可以定义任意长度的序列,并且可以在序列的每个步骤接受多种关系类型,但是我们目前不支持发散序列((r1然后r2然后r3)或(r2然后r5然后r6))。

如果我们要对r1(传入),r2(传出),r3或r4(r3朝任一方向,r4传出)进行3步序列处理,则重复该序列最多3次,我们可以这样做像这样:

MATCH (n:Node {name: 'n1'})
CALL apoc.path.expandConfig(n, {relationshipFilter:'<r1, r2>, r3 | r4>', minLevel:1, maxLevel:9) YIELD path
RETURN path

请注意,我们可以为过滤器中的每个关系提供不同的方向,如果我们不在乎方向,则可以完全忽略箭头。

标签过滤更为复杂,但到目前为止,我在示例中还没有看到对标签过滤的任何需求。

答案 1 :(得分:0)

您的查询返回所有路径,因为您的WHERE子句(Filter运算符)在VarLengthExpand运算符之前应用:

+-----------------------+----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+
| Operator              | Estimated Rows | Rows | DB Hits | Page Cache Hits | Page Cache Misses | Page Cache Hit Ratio | Variables                  | Other                                                                                                      |
+-----------------------+----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+
| +ProduceResults       |              0 |    4 |       0 |               0 |                 0 |               0.0000 | anon[32], anon[41], n, p   |                                                                                                            |
| |                     +----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+
| +Projection           |              0 |    4 |       0 |               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 |               0.0000 | anon[32], anon[41] -- n    | (n)-[:*..2]->()                                                                                            |
| |                     +----------------+------+---------+-----------------+-------------------+----------------------+----------------------------+------------------------------------------------------------------------------------------------------------+
| +Filter               |              0 |    1 |       6 |               0 |                 0 |               0.0000 | n                          | n.name = {  AUTOSTRING0}; GetDegree(Variable(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