Node2Vec

Node2Vec 是一种节点嵌入算法,它根据图中的随机游走计算节点的向量表示。邻域是通过随机游走进行采样的。算法利用大量的随机邻域样本训练一个单隐藏层神经网络。训练神经网络的目的是根据另一个节点的出现情况,预测某个节点出现在游走序列中的可能性。

有关此算法的更多信息,请参阅

随机游走 (Random Walks)

Node2Vec 算法的一个核心概念是二阶随机游走。随机游走模拟了图的遍历过程,其中被遍历的关系是随机选择的。在经典的随机游走中,每个关系被选中的概率相同(或加权相同)。这种概率不受之前访问过的节点影响。然而,二阶随机游走的概念试图根据当前访问的节点 v、当前节点之前的访问节点 t 以及候选关系的目标节点 x 来建模转移概率。因此,Node2Vec 随机游走受两个参数影响:returnFactor(返回因子)和 inOutFactor(进出因子)。

  • 如果 t 等于 x,即随机游走返回到之前访问的节点时,使用 returnFactor

  • 如果从 tx 的距离等于 2,即游走进一步远离节点 t 时,使用 inOutFactor

Visuzalition of random walk parameters

在随机游走期间遍历关系的概率可以通过指定 relationshipWeightProperty 进一步受到影响。大于 1 的关系属性值将增加遍历该关系的概率,介于 0 和 1 之间的属性值将降低该概率。

对于图中的每个节点,Node2Vec 都会生成一系列以该节点为起点的随机游走。每个节点的随机游走次数可以通过 walkPerNode 配置参数进行调整,游走长度则由 walkLength 参数控制。

语法

本节介绍执行 Node2Vec 算法所使用的语法。

运行 Node2Vec。
CALL Neo4j_Graph_Analytics.graph.node2vec(
  'CPU_X64_XS',                    (1)
  {
    ['defaultTablePrefix': '...',] (2)
    'project': {...},              (3)
    'compute': {...},              (4)
    'write':   {...}               (5)
  }
);
1 计算池选择器。
2 表引用的可选前缀。
3 项目配置。
4 计算配置。
5 写入配置。
表 1. 参数
名称 类型 默认 可选 描述

computePoolSelector

字符串

不适用

用于运行 Node2Vec 作业的计算池选择器。

配置

Map

{}

用于图项目、算法计算和结果回写的配置。

配置映射由以下三个条目组成。

有关以下项目配置的更多详细信息,请参阅 项目文档
表 2. 项目配置
名称 类型

nodeTables

节点表列表。

relationshipTables

关系类型到关系表的映射。

表 3. 计算配置
名称 类型 默认 可选 描述

walkLength

整数

80

单次随机游走的步数。

walksPerNode

整数

10

为每个节点生成的随机游走次数。

inOutFactor

浮点数

1.0

随机游走倾向于停留在起始节点附近还是在图中向外扩散。值越大,越倾向于局部停留。

returnFactor

浮点数

1.0

随机游走倾向于返回上次访问的节点的程度。低于 1.0 的值表示倾向性更高。

relationshipWeightProperty

字符串

null

用作权重的关系属性名称,用于影响随机游走的概率。权重需要 >= 0。如果未指定,算法将以无权重方式运行。

windowSize

整数

10

训练神经网络时上下文窗口的大小。

negativeSamplingRate

整数

5

为每个正样本生成的负样本数量。

positiveSamplingFactor

浮点数

0.001

影响正样本分布的因子。较高的值会增加高频节点被下采样的概率。

negativeSamplingExponent

浮点数

0.75

应用于节点频率以获得负采样分布的指数。值为 1.0 时按频率比例采样,值为 0.0 时每个节点被采样的概率相等。

embeddingDimension

整数

128

计算出的节点嵌入的大小。

embeddingInitializer

字符串

NORMALIZED

嵌入初始化方法。值从范围 [-a, a] 中均匀采样。使用 NORMALIZED 时,a=0.5/embeddingDimension;使用 UNIFORM 时,a=1

iterations (迭代次数)

整数

1

训练迭代次数。迭代次数越高,采样的随机游走就越多,因此游走集合通常会更具代表性,覆盖整个图。

initialLearningRate

浮点数

0.01

神经网络训练初始使用的学习率。学习率在每次训练迭代后都会降低。

minLearningRate

浮点数

0.0001

训练期间学习率降低时的下限。

randomSeed

整数

random

用于生成随机游走的种子值,这些随机游走被用作神经网络的训练集。请注意,生成的嵌入仍然是非确定性的。

walkBufferSize

整数

1000

开始训练前要完成的随机游走次数。

关于下文写入配置的更多详细信息,请参考 写入文档
表 4. 写入配置
名称 类型 默认 可选 描述

nodeLabel

字符串

不适用

内存中图中用于写入节点属性的节点标签。

nodeProperty

字符串

'node2vec'

将回写到 Snowflake 数据库的节点属性。

outputTable

字符串

不适用

Snowflake 数据库中写入节点属性的表。

示例

在本节中,我们将展示在具体图上运行 Node2Vec 算法的示例。目的是说明结果的样子,并提供在实际环境中使用该算法的指南。我们将通过一个包含少量节点并以特定模式连接的小型知识图来演示。示例图如下所示:

Visualization of the example graph
以下 SQL 语句将在 Snowflake 数据库中创建示例图表:
CREATE OR REPLACE TABLE EXAMPLE_DB.DATA_SCHEMA.PERSONS (NODEID VARCHAR);
INSERT INTO EXAMPLE_DB.DATA_SCHEMA.PERSONS VALUES
  ('Alice'),
  ('Bob'),
  ('Carol'),
  ('Dave'),
  ('Eve');

CREATE OR REPLACE TABLE EXAMPLE_DB.DATA_SCHEMA.INSTRUMENTS (NODEID VARCHAR);
INSERT INTO EXAMPLE_DB.DATA_SCHEMA.INSTRUMENTS VALUES
  ('Guitar'),
  ('Synthesizer'),
  ('Bongos'),
  ('Trumpet');

CREATE OR REPLACE TABLE EXAMPLE_DB.DATA_SCHEMA.LIKES (SOURCENODEID VARCHAR, TARGETNODEID VARCHAR, WEIGHT FLOAT);
INSERT INTO EXAMPLE_DB.DATA_SCHEMA.LIKES VALUES
  ('Alice', 'Guitar',      1.0),
  ('Alice', 'Synthesizer', 1.0),
  ('Alice', 'Bongos',      0.5),
  ('Bob',   'Guitar',      1.0),
  ('Bob',   'Synthesizer', 1.0),
  ('Carol', 'Bongos',      1.0),
  ('Dave',  'Guitar',      1.0),
  ('Dave',  'Trumpet',     1.5),
  ('Dave',  'Bongos',      1.0);

这个二分图有两个节点集:人 (Person) 节点和乐器 (Instrument) 节点。这两个节点集通过 LIKES 关系连接。每条关系都始于一个 Person 节点,并终止于一个 Instrument 节点。

运行作业

要运行查询,需要为应用程序、您的消费者角色和您的环境设置必要的权限。请参阅 入门 页面以了解更多信息。

我们还假设应用程序名称为默认的 Neo4j_Graph_Analytics。如果您在安装过程中选择了不同的应用程序名称,请将其替换为该名称。

以下代码将运行一个 Node2Vec 作业:
CALL Neo4j_Graph_Analytics.graph.node2vec('CPU_X64_XS', {
    'defaultTablePrefix': 'EXAMPLE_DB.DATA_SCHEMA',
    'project': {
        'nodeTables': [ 'PERSONS', 'INSTRUMENTS' ],
        'relationshipTables': {
            'LIKES': {
                'sourceTable': 'PERSONS',
                'targetTable': 'INSTRUMENTS'
            }
        }
    },
    'compute': {
        'embeddingDimension': 2
    },
    'write': [{
        'nodeLabel': 'PERSONS',
        'outputTable': 'PERSON_EMBEDDINGS'
    }]
});
表 5. 结果
JOB_ID JOB_STATUS JOB_START JOB_END JOB_RESULT

job_9f036be61fe043dbbef168b9bae4da25

SUCCESS

2025-07-17 08:43:17.050

2025-07-17 08:43:21.622

 {
  "node2vec_1": {
    "computeMillis": 33,
    "configuration": {
    "concurrency": 6,
    "embeddingDimension": 2,
    "embeddingInitializer": "NORMALIZED",
    "inOutFactor": 1,
    "initialLearningRate": 0.01,
    "iterations": 1,
    "minLearningRate": 1.000000000000000e-04,
    "resultProperty": "node2vec",
    "negativeSamplingExponent": 0.75,
    "negativeSamplingRate": 5,
    "nodeLabels": [
    "*"
    ],
    "positiveSamplingFactor": 0.001,
    "relationshipTypes": [
      "*"
    ],
    "returnFactor": 1,
    "walkBufferSize": 1000,
    "walkLength": 80,
    "walksPerNode": 10,
    "windowSize": 10
    },
    "lossPerIteration": [
      8.362697137375363
    ]
  },
  "project_1": {
    "graphName": "snowgraph",
    "nodeCount": 9,
    "nodeLabels": ...,
    "nodeMillis": 189,
    "relationshipCount": 9,
    "relationshipMillis": 296,
    "relationshipTypes": ...,
    "totalMillis": 485
  },
  "write_node_property_1": {
    "copyIntoTableMillis": 915,
    "nodeLabel": "PERSONS",
    "nodeProperty": "node2vec",
    "outputTable": "EXAMPLE_DB.DATA_SCHEMA.PERSON_EMBEDDINGS",
    "rowsWritten": 5,
    "stageUploadMillis": 583,
    "writeMillis": 1714
  }
}

返回的结果包含有关作业执行和结果分布的信息。此外,每个节点的嵌入已写回 Snowflake 数据库。我们可以像这样进行查询:

SELECT * FROM EXAMPLE_DB.DATA_SCHEMA.PERSON_EMBEDDINGS;
表 6. 结果
NODEID NODE2VEC

Alice

[-7.200873643159866e-02, -1.017554104328156e-01]

Bob

[-7.187437266111374e-02, 1.439279913902283e-01]

Carol

[-7.191916555166245e-02, 2.287001907825470e-01]

Dave

[-7.068923115730286e-02, 1.508352905511856e-01]

Eve

[-7.218790799379349e-02, 2.373333722352982e-01]

该算法的结果并不直观,因为节点嵌入格式是节点在其邻域内的数学抽象,专为机器学习程序设计。我们可以看到嵌入包含两个元素(如使用 embeddingDimension 配置的那样),且数值相对较小(它们都处于 [-1, 1] 范围内)。

由于算法的随机性,每次运行的结果会有所不同。然而,这并不意味着两个节点嵌入之间的成对距离也会发生同等程度的变化。