如何在Neo4j中找到关键节点?

如何在Neo4j中找到关键节点?,neo4j,cypher,Neo4j,Cypher,假设一个非常简单的图 (A)->(B)->(D)->(E)|(A)->(C)->(D)->(E) 如果你把它形象化的话,它看起来会像- 图中的关键节点是这样一个节点:如果删除它,现在将有2个图。(又名单点故障) 所以在这个例子中,E不是关键的,因为它是一个叶子,而B和C不是关键的,因为a和D仍然由另一个节点连接。但是,D很关键,因为删除它将使E从图的其余部分孤立 使用Cypher,如何找到关键节点?(在本例中,D) 我的第一反应是选择所有路径,并计算每个节点被触摸的次数,但这将是可怕的、低效的

假设一个非常简单的图

(A)->(B)->(D)->(E)|(A)->(C)->(D)->(E)

如果你把它形象化的话,它看起来会像
-

图中的关键节点是这样一个节点:如果删除它,现在将有2个图。(又名单点故障)

所以在这个例子中,E不是关键的,因为它是一个叶子,而B和C不是关键的,因为a和D仍然由另一个节点连接。但是,D很关键,因为删除它将使E从图的其余部分孤立

使用Cypher,如何找到关键节点?(在本例中,D)


我的第一反应是选择所有路径,并计算每个节点被触摸的次数,但这将是可怕的、低效的和不可靠的。我的第二个直觉类似于
,其中没有(路径中的n不是其他路径中的n)
,但即使我能找出如何使其工作,我也不知道路径中的哪个节点是关键的


我找到了blog,但它似乎假设您已经知道一些关于关键节点的信息

首先,您需要确定图形中节点的类型:如果所有节点都是同一类型,那么您可以计算它们的所有关系(或特定关系);如果一个节点有n个以上的关系(可能是2个),那么它可能是一个关键节点,否则这个节点就不是关键节点

但是,如果有1种以上的节点类型,则需要确定哪种节点和关系更重要,然后查询每种节点和关系,最后计算它们与所有类型节点或特定节点的关系(所有关系或特定关系)

MATCH (n)-[r]->() RETURN COUNT(r)

如果该节点被认为不重要,则可以继续删除该节点。

我找到了如何进行基于路径的过滤,其中每个可能路径上的条件都必须为真。您可以在谓词中使用模式识别来过滤所有路径。(我对我的集合使用合理的路径长度限制来限制失控。如果我的图形中存在备用路径,我预计会有一个较短的迂回。因此,请根据您的预期进行调整)


我也尝试过像这样使用所有最短路径,但在我的示例集中,性能实际上更差。你的里程数非常适合我

MATCH (a)-[*..10]->(c)-[*..10]->(b) 
WHERE ALL(p in allShortestPaths((a)-[*..20]->(b)) WHERE c in NODES(p)) 
RETURN DISTINCT c

我们可以通过其定义来实现这一点:

图中的关键节点是这样一个节点:如果删除它,现在将(至少)有2个图

或者换句话说,如果所有节点最初都可以彼此访问,并且如果我们移除一个节点,并且这会改变图中任何其他节点可以访问的节点数量,那么移除的节点就是一个关键节点

仅通过Cypher尝试此操作的最大障碍是Cypher可变长度路径匹配被设计为查找所有可能的路径,因此在查找所有可到达的节点时效率很低

通过使用,我们可以更改遍历过程中使用的唯一性,这样我们就可以只找到每个不同节点的一条路径,而忽略所有其他路径,从而减少我们需要探索的路径数量,从而更快地找到图中所有可到达的节点

使用此方法,我们可以首先计算图中的所有节点,然后针对每个节点,查看是否在扩展期间将该节点列入黑名单(有效地查看移除该节点时发生的情况)会导致从另一个节点进行的扩展比整个图中的要少(-1,当然,对于我们“移除”的节点)

为了使用这种方法,您需要使用比2018年夏季版本更新的APOC版本(3.3.x行>=3.3.0.4,或3.4.x行>=3.4.0.2),因为我们需要的
blacklistNodes
功能是随此版本添加的

这里是一般的方法,假设我们考虑所有节点,并且图中的所有节点最初都可以彼此访问

MATCH (n)
WITH collect(n) as allNodes
WITH allNodes, size(allNodes) - 1 as totalNodes, allNodes[..2] as startNodes
// using total as one less than the actual total since we're 'removing' a node.
// 2 potential start nodes so we always have one if the other is to be removed.
UNWIND allNodes as nodeToRemove
// we now have each node in the graph on its row, we'll try removing each one
WITH [node in startNodes WHERE node <> nodeToRemove][0] as startNode, nodeToRemove, totalNodes
CALL apoc.path.subgraphNodes(startNode, {blacklistNodes:[nodeToRemove]}) YIELD node
WITH totalNodes, nodeToRemove, count(node) as reachableNodes
WHERE totalNodes <> reachableNodes
RETURN nodeToRemove as criticalNode
匹配(n)
使用collect(n)作为所有节点
使用allNodes,大小(allNodes)-1作为totalNodes,allNodes[…2]作为startNodes
//因为我们正在“删除”一个节点,所以使用的总计比实际总计少一个。
//2个潜在的开始节点,因此如果要删除另一个,我们总是有一个。
将所有节点作为节点展开删除
//现在图形中的每个节点都位于其行上,我们将尝试删除每个节点
将[node in startNodes WHERE node nodeToRemove][0]作为startNode、nodeToRemove、totalNodes
调用apoc.path.subgraphNodes(startNode,{blacklistNodes:[nodeToRemove]})产生节点
使用totalNodes、nodeToRemove,将(节点)计数为可访问节点
其中totalNodes可到达节点
返回nodeToRemove作为criticalNode

请记住,关键节点问题是NP完全问题,这种问题不会有快速的解决方案可以扩展。@InverseFalcon True,但我能想到的一切都非常容易出错。我不希望图太大,我只需要一个我可以信任的解决方案是正确的。如何通过关系计数判断节点是否关键?这似乎更容易出错。
MATCH (n)
WITH collect(n) as allNodes
WITH allNodes, size(allNodes) - 1 as totalNodes, allNodes[..2] as startNodes
// using total as one less than the actual total since we're 'removing' a node.
// 2 potential start nodes so we always have one if the other is to be removed.
UNWIND allNodes as nodeToRemove
// we now have each node in the graph on its row, we'll try removing each one
WITH [node in startNodes WHERE node <> nodeToRemove][0] as startNode, nodeToRemove, totalNodes
CALL apoc.path.subgraphNodes(startNode, {blacklistNodes:[nodeToRemove]}) YIELD node
WITH totalNodes, nodeToRemove, count(node) as reachableNodes
WHERE totalNodes <> reachableNodes
RETURN nodeToRemove as criticalNode