最近想验证一个图结构的连通性,查阅很多资料跑通了一个方法,记录一下。
使用APOC函数来标记连通组件
使用apoc.periodic.iterate和apoc.path.expandConfig
CALL apoc.periodic.iterate(
"MATCH (n) WHERE n.componentId IS NULL RETURN n",
"CALL apoc.path.expandConfig(n, {relationshipFilter: '>', uniqueness: 'NODE_GLOBAL'}) YIELD path
WITH n, LAST(nodes(path)) AS lastNode, COUNT(*) AS componentId
SET lastNode.componentId = componentId",
{batchSize:1000, parallel:false}
);
第一个参数:"MATCH (n) WHERE n.componentId IS NULL RETURN n"
这个查询找到所有还没有分配componentId的节点。componentId是用来标记节点属于哪个连通组件的属性。
第二个参数:这是一系列操作,将对第一个参数返回的每个节点n执行。
"CALL apoc.path.expandConfig(n, {relationshipFilter: '>', uniqueness: 'NODE_GLOBAL'}) YIELD path WITH n, LAST(nodes(path)) AS lastNode, COUNT(*) AS componentId SET lastNode.componentId = componentId"
这里使用的apoc.path.expandConfig是一个过程,用于从特定节点开始,根据给定的配置遍历图。这里的配置指定了关系方向为'>'(考虑任何类型的出边),并设置uniqueness: 'NODE_GLOBAL'来确保每个节点在全局范围内只被访问一次。
YIELD path从expandConfig过程中获取每条路径。
WITH n, LAST(nodes(path)) AS lastNode, COUNT(*) AS componentId使用LAST(nodes(path))找到路径上的最后一个节点,并计算到目前为止已处理的路径数(作为连通组件的ID)。
SET lastNode.componentId = componentId将计算出的componentId设置为路径中最后一个节点的属性,从而标记它所属的连通组件。
{batchSize:1000, parallel:false}
batchSize: 1000意味着每批处理1000个节点。
parallel: false指定不并行执行,确保数据处理的有序性。
查询连通组件数量
MATCH (n)
WHERE n.componentId IS NOT NULL
RETURN COUNT(DISTINCT n.componentId) AS NumberOfComponents;
WHERE n.componentId IS NOT NULL只选择那些已经有componentId属性的节点。componentId是之前步骤中分配给每个节点的属性,用于标识该节点属于哪一个连通组件。如果一个节点的componentId不为空,这意味着该节点已经被分配到了一个连通组件中。
RETURN COUNT(DISTINCT n.componentId) AS NumberOfComponents
COUNT(DISTINCT n.componentId)是一个聚合函数,用来计算不重复的componentId值的数量。由于每个连通组件的所有节点都会共享相同的componentId,这个计数就等于图中连通组件的总数。
AS NumberOfComponents是一个别名(alias),用于为返回的计数值命名