Skip to Content
扩展GDS 扩展

GDS(图数据科学)扩展

自 NeuG v0.1.3 起,我们引入了 GDS 扩展,它提供了一系列在投影子图上运行的图算法。 它通过 CALL 接口,直接在 NeuG 内部支持常见的分析工作负载——社区发现、中心性分析、最短路径计算。

快速入门

-- 1. 加载图数据科学(GDS)扩展 LOAD gds; -- 2. 投影一个子图 CALL project_graph( 'social', ['person'], [ '[person, knows, person]' ] ); -- 3. 运行一个算法 CALL page_rank('social', {max_iterations: 20}) RETURN node.fName, rank; -- 4. 清理资源 CALL drop_projected_graph('social');

图投影

在运行任何 GDS 算法之前,您必须创建一个 命名空间(投影图) —— 即一个具名的子图视图,用于定义该算法所操作的节点标签、边三元组以及可选的谓词。

例如:

CALL project_graph( 'social', ['person'], [ '[person, knows, person]' ] );

随后,生成的命名空间可直接传入 GDS 算法中使用:

CALL page_rank('social', {max_iterations: 20}) RETURN node.fName, rank;

命名空间的创建与管理属于 NeuG 的通用功能,并非 GDS 扩展所特有。

有关以下内容的完整文档:

  • 使用 project_graph 创建命名空间;
  • 使用谓词对节点和关系进行过滤;
  • 通过 Cypher 查询命名空间;
  • 使用 show_projected_graphsprojected_graph_info 检查命名空间;
  • 使用 drop_projected_graph 删除命名空间;
  • 命名空间的持久化及模式/数据更新;

请参阅 命名空间

算法

所有算法均遵循相同的调用约定:

CALL <algorithm_name>('<projected_graph>', {<options>}) RETURN <columns>;

每个算法均返回一个 node 列(匹配的节点)以及一个或多个结果列。node 列的类型为 NODE,因此您可在 RETURN 子句中通过 node.<property> 访问节点属性。

注意: 大多数算法(标签传播算法 Label Propagation、Leiden 算法和 Louvain 算法除外)要求输入一个同构图子图——即仅包含一种节点标签,且边三元组也仅有一种,其源节点标签与目标节点标签均需与该节点标签一致。

PageRank

计算每个节点的 PageRank 中心性得分。得分越高表示该节点在图中的影响力越大。

CALL page_rank('<graph_name>', {<options>}) RETURN node, rank;

选项:

选项类型默认值描述
damping_factorDOUBLE0.85跟随链接的概率(相对于随机跳转)
max_iterationsINT20最大迭代次数
directedBOOLfalse是否将边视为有向边
concurrencyINTCPU 核心数并行执行的线程数

输出列:

类型描述
nodeNODE节点
rankDOUBLEPageRank 得分

示例:

CALL project_graph('social', ['person'], {'[person, knows, person]': ''}); LOAD gds; CALL page_rank('social', {damping_factor: 0.85, max_iterations: 30}) RETURN node.fName, rank ORDER BY rank DESC;

谓词支持: 同时支持节点和边谓词。


BFS(广度优先搜索)

计算从源节点到所有可达节点的最短跳数距离。

CALL bfs('<graph_name>', {<options>}) RETURN node, distance;

选项:

选项类型默认值描述
sourceSTRING(必填)源节点的主键值
directedBOOLfalse是否仅按边的存储方向进行遍历
concurrencyINTCPU 核心数线程数

输出列:

类型描述
nodeNODE节点
distanceINT64从源节点出发的跳数
pathPATH从源节点到该节点的最短路径(可选,仅在 YIELD 时返回)

示例:

CALL bfs('social', {source: '0'}) RETURN node.fName, distance ORDER BY distance;

返回路径:

-- 返回实际的最短路径 CALL bfs('social', {source: '0'}) YIELD node, distance, path RETURN node.fName, distance, path; -- 提取路径详情 CALL bfs('social', {source: '0'}) YIELD node, distance, path RETURN node.fName, distance, nodes(path) AS path_nodes, relationships(path) AS path_edges;

谓词支持: 支持节点和边谓词。


SSSP(单源最短路径)

计算从源节点到所有可达节点的最短加权路径距离。如果没有权重属性,其行为类似于 BFS,但返回 DOUBLE 类型的距离。

CALL sssp('<graph_name>', {<options>}) RETURN node, distance;

选项:

选项类型默认值描述
sourceSTRING(必填)源节点的主键值
directedBOOLfalse是否仅按边的存储方向遍历
weightSTRING""用作权重的边属性名称(空表示单位权重)
concurrencyINTCPU 核心数线程数

输出列:

类型描述
nodeNODE节点
distanceDOUBLE从源节点出发的最短路径距离
pathPATH从源节点到该节点的最短路径(可选,仅在 YIELD 时返回)

示例:

CALL sssp('social', {source: '0', weight: 'cost', directed: true}) RETURN node.fName, distance;

返回路径:

-- 返回实际的最短路径 CALL sssp('social', {source: '0', weight: 'cost'}) YIELD node, distance, path RETURN node.fName, distance, path; -- 查找通往特定目标节点的路径 CALL sssp('social', {source: '0', weight: 'cost'}) YIELD node, distance, path WHERE node.id = '42' RETURN distance, path;

谓词支持: 同时支持节点和边谓词。


WCC(弱连通分量)

为每个节点分配一个分量 ID。同一个连通分量中的节点共享相同的 ID。

CALL wcc('<graph_name>', {<options>}) RETURN node, comp;

选项:

选项类型默认值描述
concurrencyINTCPU 核心数线程数

输出列:

类型描述
nodeNODE节点
compINT64分量标识符

示例:

CALL wcc('social', {concurrency: 8}) RETURN node.fName, comp ORDER BY comp;

谓词支持: 同时支持节点和边谓词。


LCC(局部聚类系数)

衡量一个节点的邻居形成完全图(团)的紧密程度。取值范围为 0.0 到 1.0。

CALL lcc('<graph_name>', {<options>}) RETURN node, lcc;

选项:

选项类型默认值描述
directedBOOLfalse是否计算有向聚类系数
degree_thresholdINTMAX_INT跳过度数高于此阈值的节点
concurrencyINTCPU cores并行执行的线程数

输出列:

类型描述
nodeNODE节点
lccDOUBLE局部聚类系数

示例:

CALL lcc('social', {degree_threshold: 1000}) RETURN node.fName, lcc ORDER BY lcc DESC;

谓词支持: 支持节点和边谓词。


K核分解

计算每个节点的核数。若一个节点属于 k-核(即每个节点度数均 >= k 的极大子图),但不属于 (k+1)-核,则该节点的核数为 k

CALL kcore('<graph_name>', {<options>}) RETURN node, core;

选项:

选项类型默认值描述
kINT2最小核数阈值(必须 >= 0)
concurrencyINTCPU 核数线程数

输出列:

类型描述
nodeNODE节点
coreINT64节点的核数

示例:

CALL kcore('social', {k: 3}) RETURN node.fName, core ORDER BY core DESC;

谓词支持: 支持节点和边谓词。


CDLP(基于标签传播的社区发现)

一种通过网络传播标签来进行社区发现的算法。 每个节点最初被赋予一个唯一的标签;在每次迭代中,每个节点采用其邻居中出现频率最高的标签。

CALL cdlp('<graph_name>', {<options>}) RETURN node, label;

可选参数:

参数类型默认值描述
max_iterationsINT5标签传播的最大迭代次数
concurrencyINT1并行执行所使用的线程数

输出列:

列名类型描述
nodeNODE节点
labelINT64分配给该节点的社区标签

示例:

CALL project_graph( 'study_net', {'person': 'n.age > 20', 'organisation': 'n.name = "MIT"'}, {'[person, studyAt, organisation]': 'r.year > 2010'} ); LOAD gds; CALL cdlp('study_net', {concurrency: 10}) RETURN node.id, node.fName, node.name, label;

谓词支持: 同时支持节点谓词和边谓词。

注意: 当前 CDLP 与其他大多数算法一样,仅支持同构图。 对多标签的支持计划在后续版本中推出。

Louvain

一种社区发现算法,通过迭代地将节点在社区之间移动并聚合图形成超节点,以优化模块度(modularity)。

Louvain 支持多标签图(multi-label graphs)——即包含多个顶点标签和多个边三元组的投影图,会被视为一个统一的图进行处理。

CALL louvain('<graph_name>', {<options>}) RETURN node, community;

选项(Options):

选项类型默认值描述
resolutionDOUBLE1.0分辨率参数(gamma)。值大于 1 倾向于生成更小的社区;小于 1 倾向于生成更大的社区
directedBOOLfalse是否将图视为有向图
thresholdDOUBLE1e-7模块度增益收敛阈值
concurrencyINTCPU 核心数并行执行所用线程数
initial_community_propertySTRING""用于初始化社区 ID 的顶点属性名,适用于增量更新。设置后,默认启用“冻结分配(freeze-assign)”模式,即已存在的顶点社区归属被冻结。
allow_relocationBOOLfalse若为 true,允许已存在的顶点被重新分配至其他社区(热启动模式,warm-start mode);若为 false(默认),已存在顶点的社区归属保持不变。
weightSTRING""用作边权重的边属性名。若设置,算法将采用加权模块度;若为空(默认),所有边权重均为 1.0(无权图)。

输出列(Output columns):

列名类型描述
nodeNODE节点
communityINT64社区 ID(从 0 开始编号)
previous_communityINT64上一次运行所得的社区 ID。仅当设置了 initial_community_property,或该顶点此前未被分配过社区时,此字段才非 NULL。

示例(单标签图):

CALL louvain('social', {resolution: 1.0, concurrency: 8}) RETURN node.fName, community ORDER BY community;

示例(多标签图):

CALL project_graph( 'social_multi', ['person', 'organisation'], {'[person, knows, person]': '', '[person, studyAt, organisation]': ''} ); CALL louvain('social_multi', {concurrency: 8}) RETURN node.fName, community ORDER BY community;

增量模式(Incremental mode): 为在多次运行中保持社区 ID 一致,可将结果写回顶点属性,并在后续调用中通过 initial_community_property 参数复用。默认采用冻结分配(freeze-assign)模式:已存在顶点的社区归属保持不变,仅对无先前社区归属的新顶点进行聚类。

-- 1. 添加一列用于存储社区 ID ALTER TABLE person ADD COLUMN comm INT64 DEFAULT -1; -- 2. 首次运行:计算社区并将结果写回顶点属性 CALL louvain('social', {concurrency: 8}) YIELD node, community MATCH (n:person) WHERE n.id = node.id SET n.comm = community; -- 3. 使用冻结分配(默认)再次运行:旧顶点社区冻结,新顶点参与聚类 CALL louvain('social', {initial_community_property: 'comm', concurrency: 8}) RETURN node.fName, community ORDER BY community; -- 3b. 替代方案:热启动模式(允许旧顶点被重新分配) CALL louvain('social', {initial_community_property: 'comm', allow_relocation: true, concurrency: 8}) RETURN node.fName, community ORDER BY community;

增量差分分析(Incremental delta analysis): 当使用 initial_community_property 运行时,可通过 YIELD 获取可选的 previous_community 列,以逐顶点分析社区归属变化。在冻结分配模式下,新顶点的 previous_communityNULL,而已存在顶点的 previous_community 等于其当前 community

-- 迁移矩阵:统计顶点在社区间的迁移情况 CALL louvain('social', {initial_community_property: 'comm', allow_relocation: true, concurrency: 8}) YIELD node, community, previous_community RETURN previous_community, community, count(*) AS members ORDER BY previous_community, community; -- 新增顶点(冻结分配模式):previous_community 为 NULL CALL louvain('social', {initial_community_property: 'comm', concurrency: 8}) YIELD node, community, previous_community WHERE previous_community IS NULL RETURN node.id, community;

谓词支持(Predicate support): 同时支持节点谓词与边谓词。

Leiden

一种社区发现算法,在 Louvain 算法基础上增加了细化阶段(refinement phase),从而提升社区划分质量。该细化阶段允许在执行过程中对已有社区进行拆分,因而能更准确地识别小型社区,并生成更高品质的社区划分结果。

Leiden 支持多标签图(multi-label graphs)——即一个投影图中可包含多种顶点标签及多种边三元组,系统将其统一视为单个图进行处理。

CALL leiden('<graph_name>', {<options>}) RETURN node, community;

参数选项(Options):

选项类型默认值描述
resolutionDOUBLE1.0分辨率参数(gamma)。值 > 1 倾向于发现更小的社区;值 < 1 倾向于发现更大的社区
directedBOOLfalse是否将图视为有向图
thresholdDOUBLE1e-7模块度增益收敛阈值
concurrencyINTCPU 核心数并行执行所用线程数
initial_community_propertySTRING""用于指定顶点属性名,以初始化社区 ID,支持增量式更新。若设置该参数,则默认启用 冻结分配模式(freeze-assign mode),即已存在顶点的社区归属被冻结(保持不变)。
allow_relocationBOOLfalse若为 true,则允许已存在顶点被重新分配至其他社区(即“热启动模式”,warm-start mode);若为 false(默认),则已存在顶点的社区归属保持不变。
weightSTRING""指定边属性名,作为边权重。若设置该参数,算法将采用加权模块度(weighted modularity);若为空(默认),所有边权重均为 1.0(即无权图)。

输出列(Output columns):

列名类型描述
nodeNODE顶点
communityINT64社区 ID(从 0 开始编号)
previous_communityINT64上一次运行所得的社区 ID。仅当设置了 initial_community_property,或该顶点此前未被分配过社区时,该字段才非 NULL。

示例(单标签图):

CALL leiden('social', {resolution: 1.5, concurrency: 8}) RETURN node.fName, community ORDER BY community;

示例(多标签图):

CALL project_graph( 'social_multi', ['person', 'organisation'], {'[person, knows, person]': '', '[person, studyAt, organisation]': ''} ); CALL leiden('social_multi', {concurrency: 8}) RETURN node.fName, community ORDER BY community;

增量模式(Incremental mode): 为在多次运行间保持社区 ID 的一致性,可将结果写回顶点属性,并在后续调用中通过 initial_community_property 参数复用该属性。默认采用 冻结分配模式(freeze-assign mode):已存在顶点的社区归属保持不变,仅对新增顶点(此前无社区归属)执行聚类。

-- 1. 添加一列属性用于存储社区 ID ALTER TABLE person ADD COLUMN comm INT64 DEFAULT -1; -- 2. 首次运行:计算社区并写回顶点属性 CALL leiden('social', {concurrency: 8}) YIELD node, community MATCH (n:person) WHERE n.id = node.id SET n.comm = community; -- 3. 使用冻结分配模式(默认)再次运行:旧顶点社区冻结,新顶点被分配 CALL leiden('social', {initial_community_property: 'comm', concurrency: 8}) RETURN node.fName, community ORDER BY community; -- 3b. 替代方案:热启动模式(允许旧顶点被重新分配) CALL leiden('social', {initial_community_property: 'comm', allow_relocation: true, concurrency: 8}) RETURN node.fName, community ORDER BY community;

增量差分分析(Incremental delta analysis): 当使用 initial_community_property 运行时,可通过 YIELD 子句获取可选的 previous_community 列,以逐顶点分析社区归属变化。在冻结分配模式下,新顶点的 previous_communityNULL,而已存在顶点的 previous_community 等于其当前 community

-- 迁移矩阵:统计顶点在社区间的迁移情况 CALL leiden('social', {initial_community_property: 'comm', allow_relocation: true, concurrency: 8}) YIELD node, community, previous_community RETURN previous_community, community, count(*) AS members ORDER BY previous_community, community; -- 新增顶点(冻结分配模式):previous_community 为 NULL CALL leiden('social', {initial_community_property: 'comm', concurrency: 8}) YIELD node, community, previous_community WHERE previous_community IS NULL RETURN node.id, community;

谓词支持(Predicate support): 同时支持顶点谓词与边谓词。

Leiden 与 Louvain 对比:

  • 若需更高品质的社区划分结果,或更优的小型社区检测能力,请选用 Leiden
  • 若追求极致运行速度,请选用 Louvain

最短路径返回

BFS 和 SSSP 算法除了支持返回距离外,还支持返回实际的最短路径(节点和关系的序列)。该路径以 PATH 类型返回,支持所有标准的 Cypher 路径函数。

请求路径

path 列是可选的,只有在显式 YIELD 时才会返回:

-- 不包含路径(默认,最快) CALL bfs('graph', {source: '0'}) RETURN node, distance; -- 包含路径(返回从源节点到每个节点的最短路径) CALL bfs('graph', {source: '0'}) YIELD node, distance, path RETURN node, distance, path;

处理路径

使用标准的 Cypher 路径函数来提取信息:

-- 获取路径中的节点和关系 CALL bfs('graph', {source: '0'}) YIELD node, distance, path RETURN nodes(path) AS path_nodes, relationships(path) AS path_rels, length(path) AS path_length; -- 按长度过滤路径 CALL bfs('graph', {source: '0'}) YIELD node, distance, path WHERE length(path) > 2 RETURN node, distance, path; -- 查找特定目标 CALL sssp('graph', {source: '0', weight: 'cost'}) YIELD node, distance, path WHERE node.id = '42' RETURN distance, path;

性能注意事项

  • 未 YIELD 时无额外开销:如果您不请求 path 列,与仅查询距离相比,不会产生任何性能损耗。
  • 默认为完整模式:默认情况下,路径包含所有顶点和边属性,这与标准 MATCH p = ... 查询的行为一致,以确保向后兼容性。
  • 大型结果集:当返回大量节点的路径时,请注意路径序列化会包含所有顶点和边属性,在大型图中可能会占用大量内存。

算法概览

算法CALL 名称输出列关键选项
PageRankpage_ranknode, rankdamping_factor, max_iterations, directed
BFSbfsnode, distance, pathsource(必需)、directed
SSSPssspnode, distance, pathsource(必需)、weight, directed
WCCwccnode, compconcurrency
LCClccnode, lccdirected, degree_threshold
K-Corekcorenode, corek
CDLPcdlpnode, labelmax_iterations
Louvainlouvainnode, community, previous_community可选resolution, directed, threshold, concurrency, initial_community_property, allow_relocation, weight
Leidenleidennode, community, previous_community可选resolution, directed, threshold, concurrency, initial_community_property, allow_relocation, weight

注意: BFS 和 SSSP 的 path 列为可选列,仅当显式在 YIELD 子句中指定时才返回。Louvain 和 Leiden 的 previous_community 列始终可被 YIELD,但仅当设置了 initial_community_property 时其值才非 NULL。详见各算法的独立章节说明。

常用选项

所有算法均支持 concurrency 选项,用于控制并行计算所使用的线程数。默认值因算法而异:

  • 大多数算法: 默认值为 CPU 核心数
  • 标签传播、Personalized PageRank: 默认值为 1

局限性

  • 大多数算法要求输入为同构图子图(即仅含一种节点标签和一种边三元组 [A, edge, A])。Leiden 和 Louvain 是例外,它们支持具有多种节点标签和多种边三元组的多标签图。其他算法对异构图的支持计划在后续版本中推出。
  • CDLP 目前实际上尚不支持异构图——它仅处理第一个节点标签和第一个边三元组。真正的多标签支持正在规划中。
Last updated on