如何让Neo4j考虑周期

时间:2017-02-06 00:58:20

标签: neo4j cypher

似乎Neo4j故意省略了循环,所以查询如下:

MATCH (n1)-[:R]->(n2)<-[:R]-(n1)
RETURN n1, n2;

除非在Rn1之间存在两种类型为n2的关系,否则始终不会返回任何内容(这绝对可能且是一次糟糕的黑客攻击)。

但是我有一个场景,这个周期可能会发生并且是理想的:

MATCH (n1)-[:R]->(n2)<-[:R]-(n3)
RETURN n1, n2, n3;

在此查询中,n1n3可能是相同的节点或不同的节点,它们都取决于数据(两者都有效)。实现此目的的一种方法是:

MATCH (n1)-[:R]->(n2)
MATCH (n2)<-[:R]-(n3)
RETURN n1, n2, n3;

这最后一个查询将包括所有路径甚至周期,它完全没问题。但我的情况甚至比这更复杂:

MATCH (n0)
OPTIONAL MATCH (n0)-[:R0]->(n1)-[:R]->(n2)<-[:R]-(n3)
RETURN n0, n1, n2, n3;

正如我们之前所见,在此查询中省略了周期,因此我们必须将其分解为两个OPTIONAL MATCH es:

MATCH (n0)
OPTIONAL MATCH (n0)-[:R0]->(n1)-[:R]->(n2)
OPTIONAL MATCH (n2)<-[:R]-(n3)
RETURN n0, n1, n2, n3;

但这与以前不一样(如果另一个有效)。这里第二个OPTIONAL MATCH可能不会返回任何路径,而第一个路径。换句话说,两个OPTIONAL MATCH es是独立的。

所以我的问题是:如何实现以下查询并获得结果中的循环?

MATCH (n0)
OPTIONAL MATCH (n0)-[:R0]->(n1)-[:R]->(n2)<-[:R]-(n3)
RETURN n0, n1, n2, n3;

我希望它不会太混乱!

为什么两个OPTIONAL MATCH不是答案

考虑以下节点和关系:

  1. CREATE (n0:S)-[:R]->(n1:R)<-[:R]-(n2:E)-[:R]->(n3:R:L);
  2. CREATE (n0:S)-[:R]->(n1:R:L)<-[:R]-(n2:E);
  3. CREATE (n0:S)-[:R]->(n1:R)<-[:R]-(n2:E);
  4. 在上面的示例中,以下是标签的含义(因此您可以与问题相关):

    • :S开始节点
    • :R修订
    • :E实体
    • :L最新版本

    在此示例中,每个数据记录都在:E + :R中表示,当记录更新时,会向其添加新的:R。数据的当前状态标记为:L,因此我们可以找到最新版本。

    现在,在给出的三个示例中,最后一个是无效数据,因为它没有任何:L。第一个有两个版本,第二个有一个。

    请求的查询应该:

    1. 无论
    2. 返回:S
    3. 返回所有实体及其最新版本,仅在它们具有最新版本
    4. 没有最新修订版的实体毫无意义,不应该退回
    5. 如果Neo4j支持循环,此查询将返回请求的数据:

      MATCH (n1:S)
      OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)-[:R]->(n4:R:L)
      RETURN labels(n1), labels(n3), labels(n4);
      

      上述查询的预期结果为:

      ╒════════════╤════════════╤════════════╕
      │"labels(n1)"│"labels(n3)"│"labels(n4)"│
      ╞════════════╪════════════╪════════════╡
      │["S"]       │["E"]       │["R","L"]   │
      ├────────────┼────────────┼────────────┤
      │["S"]       │["E"]       │["R","L"]   │
      ├────────────┼────────────┼────────────┤
      │["S"]       │null        │null        │
      └────────────┴────────────┴────────────┘
      

      实际结果是:

      ╒════════════╤════════════╤════════════╕
      │"labels(n1)"│"labels(n3)"│"labels(n4)"│
      ╞════════════╪════════════╪════════════╡
      │["S"]       │["E"]       │["R","L"]   │
      ├────────────┼────────────┼────────────┤
      │["S"]       │null        │null        │
      ├────────────┼────────────┼────────────┤
      │["S"]       │null        │null        │
      └────────────┴────────────┴────────────┘
      

      正如您所看到的那样,第二条路径被缩短了,因为它包含了一个循环。现在,如果我们使用两个OPTIONAL MATCH方法:

      MATCH (n1:S)
      OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)
      OPTIONAL MATCH (n3)-[:R]->(n4:R:L)
      RETURN labels(n1), labels(n3), labels(n4);
      

      结果将是:

      ╒════════════╤════════════╤════════════╕
      │"labels(n1)"│"labels(n3)"│"labels(n4)"│
      ╞════════════╪════════════╪════════════╡
      │["S"]       │["E"]       │["R","L"]   │
      ├────────────┼────────────┼────────────┤
      │["S"]       │["E"]       │["R","L"]   │
      ├────────────┼────────────┼────────────┤
      │["S"]       │["E"]       │null        │
      └────────────┴────────────┴────────────┘
      

      虽然第二种情况是固定的,但第三种情况现在是问题,那是因为两个可选条款可以独立存在。

      很抱歉这个问题很长,我试着简短一点!

3 个答案:

答案 0 :(得分:1)

[增订]

(A)基于新问题的新答案。

MATCH (s:S)-[:R]->(firstRev:R)
OPTIONAL MATCH (firstRev)<-[:R]-(e:E)
OPTIONAL MATCH (e)-[:R]->(latestRev:L)
RETURN
  LABELS(s) AS ls,
  CASE WHEN latestRev IS NOT NULL THEN LABELS(e) END AS le,
  LABELS(latestRev) AS ll;

上述查询使用2个OPTIONAL MATCH子句来允许循环(其中2 R个关系相同)。如果第二个CASE失败,le子句将返回NULL OPTIONAL MATCH值。

(B)原始答案(已废弃)

这对你有用吗?

OPTIONAL MATCH (n1)-[:R]->(n2)
OPTIONAL MATCH (n2)<-[:R]-(n3)
RETURN n1, n2, n3;

答案 1 :(得分:1)

1)您可以使用两个“选项”更正版本,并添加对节点匹配的检查:

MATCH (n1:S)
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)
OPTIONAL MATCH (n3t)-[:R]->(n4:R:L) WHERE n3t = n3
RETURN labels(n1), labels(n3t), labels(n4);

2)我认为你使用术语cycle是错误的,这会让你觉得你对数据模型有些不对劲。在您的测试数据上没有周期:

enter image description here

答案 2 :(得分:1)

如果我正确理解了这个问题,这个查询应该会为您提供您正在寻找的预期结果表:

MATCH (n1:S)
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)
WHERE (n3)-[:R]->(:R:L)
OPTIONAL MATCH (n3)-[:R]->(n4:R:L)
RETURN labels(n1), labels(n3), labels(n4)

关键是我们给第一个可选匹配的WHERE。只有当n3具有到:R:L节点的所需路径时,OPTIONAL MATCH才会匹配,并且它将计算已被OPTIONAL MATCH遍历的关系和节点。