我们可以通过其定义来解决这个问题:
在图中,关键节点是指当你移除它时,你现在会有(至少)两个图。
或者换句话说,如果最初所有节点都可以相互到达,如果我们删除一个节点,并且这改变了任何其他节点在图中可到达的节点数量,则该已删除节点为关键节点。
通过Cypher单独尝试此操作的难点在于,Cypher变量长度路径匹配旨在找到所有可能的路径,因此在查找所有可到达节点时效率不高。
使用
APOC Path expander procedures,我们可以更改遍历期间使用的唯一性,以便我们仅找到通向每个不同节点的单个路径并拒绝所有其他路径,缩减我们需要探索的路径数,从而使其在图中查找所有可到达的节点时更快。
使用此方法,我们首先可以计算出图中的所有节点,然后对于每个节点,看看在扩展过程中黑名单化该节点(有效地查看我们删除该节点会发生什么)是否会导致从另一个节点进行扩展发现少于整个图的节点数(当然要减去我们“删除”的节点数)。
您需要使用比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