Cypher - neo4j找到递归的末端节点

时间:2021-10-22 18:03:41

I'm trying to find all beginning nodes for a given node type, starting with any node in my database. These are nodes that have no relationships pointing to them.

我正在尝试查找给定节点类型的所有起始节点,从我的数据库中的任何节点开始。这些节点没有指向它们的关系。

I'm currently doing it manually, but need a recursive-type of statement to simplify and expand. Here is what I have so far, with a return statement describing what I need.

我目前正在手动执行此操作,但需要递归类型的语句来简化和扩展。这是我到目前为止所做的,返回声明描述了我的需要。

MATCH ((d1:Type1 {Name: "test1"}))
MATCH ((t1:Type2)-[:Rel1]->(h1:Type3))
MATCH ((d1)<-[ud1:Rel3]-(t1))
OPTIONAL MATCH ((h1)<-[:Rel1]-(t2:Type2))
OPTIONAL MATCH ((t2)<-[:Rel2]-(d2:Type1))
OPTIONAL MATCH ((d2)<-[ud2:Rel3]-(t3:Type2))
OPTIONAL MATCH ((t3)-[:Rel1]->(h2:Type3))
OPTIONAL MATCH ((h2)<-[:Rel1]-(t4:Type2))
OPTIONAL MATCH ((t4)<-[:Rel2]-(d3:Type1))
OPTIONAL MATCH ((d3)<-[ud3:Rel3]-(t5:Type2))

RETURN DISTINCT Type1.Name where there is no Rel3 relationship

The ask here is to navigate the recursive

这里的问题是导航递归

Type1 < -  Type2 -> Type3 <- Type2 < - Type1 < - Type2 -> Type3 <- Type2 

path, until there are no Type2s pointing to the Type1, and return the names of these Type1s.

path,直到没有指向Type1的Type2,并返回这些Type1的名称。

2 个解决方案

#1


Your query example is quite complex and contains stand-in types that make it a bit hard to understand.

您的查询示例非常复杂,并且包含使其有点难以理解的替代类型。

I think this boils down to something quite simple, you should try this:

我认为这归结为非常简单的事情,你应该试试这个:

MATCH (startingPoint:Type1 { name: "test1" })
MATCH (startingPoint)-[:relType*]->(headNode)
OPTIONAL MATCH (headNode)-[f:relType]->()
WHERE f is null;

So all this does is match from a startingPoint through any number of relationships to a headNode. How do we know that the headNode is really at the beginning? Because we insist with the OPTIONAL MATCH that it cannot be connected to anything else further upstream. We attempt to match what would be another upstream match, and then insist with the WHERE clause that it must be missing, hence headNode is really "at the top".

所以这一切都是从StartingPoint到任意数量的关系匹配到headNode。我们怎么知道headNode真的刚开始?因为我们坚持使用OPTIONAL MATCH它不能连接到更上游的任何其他东西。我们尝试匹配另一个上游匹配,然后坚持WHERE子句它必须丢失,因此headNode真的“在顶部”。

Customize this with your own relTypes and labels, and you should be able to follow this pattern.

使用您自己的relTypes和标签自定义它,您应该能够遵循这种模式。

More broadly, when you're asking about a beginning node and it not having some relationships, See also this related question.

更广泛地说,当您询问起始节点并且没有某些关系时,请参阅此相关问题。

#2


FrobberOfBits has a great answer, but doesn't address the need to navigate through mutiple nodes types recursively. I've still yet to see a syntax that allows for this type of recursive querying in Cypher.

FrobberOfBits有一个很好的答案,但没有解决递归导航多个节点类型的需要。我还没有看到允许在Cypher中进行这种类型的递归查询的语法。

The work around is to simply create a new relationship using the complex traversal, then use FrobberOfBits solution to find the headnode.

解决方法是使用复杂遍历创建新关系,然后使用FrobberOfBits解决方案查找headnode。

Here is what I came up with:

这是我想出的:

MATCH ((d1:Type1))
MATCH ((q1:Type2)-[:Rel1]->(p1:Type3))
MATCH ((d1)<-[ud1:Rel2]-(q1))
MATCH ((p1)<-[:Rel1]-(q2:Type2))
MATCH ((q2)<-[:Rel3]-(d2:Type1))
WITH  distinct d1 as child,d2 as parent
CREATE (child)<-[:ParentOf]-(parent)

This creates a new relationship type between two Type1s, removing the need to navigate through the different node types recursively, and simply allowing tree-traversal on a single node type (As FrobberOfBits masterfully explained)

这会在两个Type1之间创建一个新的关系类型,无需递归地浏览不同的节点类型,只需在单个节点类型上允许树遍历(如FrobberOfBits巧妙地解释)

Here is my resulting query using the types in the question and the above create statement, with an alternate syntax to Fibber's.

这是我使用问题中的类型和上面的create语句生成的查询,其中包含Fibber的替代语法。

MATCH((d1:Type1 {Name: "test1"}))
OPTIONAL MATCH ((d1)<-[r1:Rel1*]-(d2:Type1))
WHERE NOT (d2)<--()
return distinct d2.Name

Sorry for the poor type masking! I should have been more creative with my aliasing.

对不起,这是一种糟糕的掩饰!我的别名我应该更有创意。

#1


Your query example is quite complex and contains stand-in types that make it a bit hard to understand.

您的查询示例非常复杂,并且包含使其有点难以理解的替代类型。

I think this boils down to something quite simple, you should try this:

我认为这归结为非常简单的事情,你应该试试这个:

MATCH (startingPoint:Type1 { name: "test1" })
MATCH (startingPoint)-[:relType*]->(headNode)
OPTIONAL MATCH (headNode)-[f:relType]->()
WHERE f is null;

So all this does is match from a startingPoint through any number of relationships to a headNode. How do we know that the headNode is really at the beginning? Because we insist with the OPTIONAL MATCH that it cannot be connected to anything else further upstream. We attempt to match what would be another upstream match, and then insist with the WHERE clause that it must be missing, hence headNode is really "at the top".

所以这一切都是从StartingPoint到任意数量的关系匹配到headNode。我们怎么知道headNode真的刚开始?因为我们坚持使用OPTIONAL MATCH它不能连接到更上游的任何其他东西。我们尝试匹配另一个上游匹配,然后坚持WHERE子句它必须丢失,因此headNode真的“在顶部”。

Customize this with your own relTypes and labels, and you should be able to follow this pattern.

使用您自己的relTypes和标签自定义它,您应该能够遵循这种模式。

More broadly, when you're asking about a beginning node and it not having some relationships, See also this related question.

更广泛地说,当您询问起始节点并且没有某些关系时,请参阅此相关问题。

#2


FrobberOfBits has a great answer, but doesn't address the need to navigate through mutiple nodes types recursively. I've still yet to see a syntax that allows for this type of recursive querying in Cypher.

FrobberOfBits有一个很好的答案,但没有解决递归导航多个节点类型的需要。我还没有看到允许在Cypher中进行这种类型的递归查询的语法。

The work around is to simply create a new relationship using the complex traversal, then use FrobberOfBits solution to find the headnode.

解决方法是使用复杂遍历创建新关系,然后使用FrobberOfBits解决方案查找headnode。

Here is what I came up with:

这是我想出的:

MATCH ((d1:Type1))
MATCH ((q1:Type2)-[:Rel1]->(p1:Type3))
MATCH ((d1)<-[ud1:Rel2]-(q1))
MATCH ((p1)<-[:Rel1]-(q2:Type2))
MATCH ((q2)<-[:Rel3]-(d2:Type1))
WITH  distinct d1 as child,d2 as parent
CREATE (child)<-[:ParentOf]-(parent)

This creates a new relationship type between two Type1s, removing the need to navigate through the different node types recursively, and simply allowing tree-traversal on a single node type (As FrobberOfBits masterfully explained)

这会在两个Type1之间创建一个新的关系类型,无需递归地浏览不同的节点类型,只需在单个节点类型上允许树遍历(如FrobberOfBits巧妙地解释)

Here is my resulting query using the types in the question and the above create statement, with an alternate syntax to Fibber's.

这是我使用问题中的类型和上面的create语句生成的查询,其中包含Fibber的替代语法。

MATCH((d1:Type1 {Name: "test1"}))
OPTIONAL MATCH ((d1)<-[r1:Rel1*]-(d2:Type1))
WHERE NOT (d2)<--()
return distinct d2.Name

Sorry for the poor type masking! I should have been more creative with my aliasing.

对不起,这是一种糟糕的掩饰!我的别名我应该更有创意。