节点相似度 (Node Similarity)

本节介绍 Neo4j Graph Analytics for Snowflake 中的节点相似度(Node Similarity)算法。该算法基于 Jaccard 和 Overlap(重叠)相似度指标。

简介

节点相似度算法根据节点所连接的对象来比较一组节点。如果两个节点共享许多相同的邻居,则认为它们是相似的。节点相似度基于 Jaccard 指标(也称为 Jaccard 相似度得分)、Overlap 系数(也称为 Szymkiewicz–Simpson 系数)以及余弦相似度(Cosine Similarity)得分来计算成对相似度。前两者最常用于无权集合,而余弦相似度则常用于加权输入。

给定两个集合 AB,Jaccard 相似度使用以下公式计算

jacard nodesim

Overlap 系数使用以下公式计算

overlap nodesim

加权情况下的公式可以在下方的加权示例中找到。

余弦相似度得分使用以下公式计算,其中当 A 和 B 为无权时,条目被隐含地赋予权重 1

cos

该算法的输入是一个包含两个不相交节点集的二分连通图。每条关系都从第一个节点集中的一个节点开始,并指向第二个节点集中的一个节点。

节点相似度算法将每个具有出站关系的节点与其它此类节点进行比较。对于每个节点 n,我们收集该节点的出站邻域 N(n),即所有满足存在从 nm 的关系的节点 m。对于每一对 nm,算法会计算该对的相似度,结果等于所选相似度指标对 N(n)N(m) 计算得出的值。

节点相似度的时间复杂度为 O(n3),空间复杂度为 O(n2)。我们以 O(n2) 的时间和空间计算并存储邻居集,然后以 O(n3) 的时间计算成对相似度得分。

为了限制内存使用,您可以指定每个节点输出结果数量的明确限制,即 'topK' 参数。它可以设置为除 0 以外的任何值。当然,您会在整体计算中损失精度,但运行时间不受影响——我们仍然必须在可能丢弃结果之前计算出结果。

算法的输出是第一个节点集中各对节点之间的新关系。相似度得分通过关系属性来表示。

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

语法

本节涵盖了执行节点相似度算法所使用的语法。

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

computePoolSelector

字符串

不适用

用于运行节点相似度作业的计算池选择器。

配置

Map

{}

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

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

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

nodeTables

节点表列表。

relationshipTables

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

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

resultProperty

字符串

'similarity'

将回写到 Snowflake 数据库的关系属性。

resultRelationshipType

字符串

'SIMILAR_TO'

用于回写到 Snowflake 数据库的关系类型。

similarityCutoff

浮点数

1e-42

结果中显示相似度得分的下限。值必须介于 0 和 1 之间。

degreeCutoff

整数

1

节点被纳入比较所需满足的节点度数的包含性下限。该值不能低于 1。

upperDegreeCutoff

整数

2147483647

节点被纳入比较所需满足的节点度数的包含性上限。该值不能低于 1。

topK

整数

10

每个节点的得分数量上限。返回 K 个最大的结果。此值不能低于 1。

bottomK

整数

10

每个节点的得分数量上限。返回 K 个最小的结果。此值不能低于 1。

topN

整数

0

计算出的得分的全局总数上限。返回 N 个最大的结果。此值不能为负数,值为 0 表示没有全局上限。

bottomN

整数

0

计算出的得分的全局总数上限。返回 N 个最小的结果。此值不能为负数,值为 0 表示没有全局上限。

relationshipWeightProperty

字符串

null

用作权重的关系属性名称。如果未指定,算法将作为无权重运行。

similarityMetric

字符串

JACCARD

用于计算相似度的指标。可以是 JACCARDOVERLAPCOSINE

useComponents

布尔值或字符串

false

如果启用,节点相似度将使用组件来提高计算性能,跳过不同组件中节点之间的比较。设置为 false(默认):算法不使用组件,而是计算整个图的相似度。设置为 true:算法使用组件,并在计算相似度之前计算这些组件。设置为 String:使用存储在图中的预计算组件,String 是表示组件的节点属性键。

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

sourceLabel

字符串

不适用

内存图中待回写关系起始节点的节点标签。

targetLabel

字符串

不适用

内存图中待回写关系结束节点的节点标签。

outputTable

字符串

不适用

关系写入的 Snowflake 数据库表。

关系类型 (relationshipType)

字符串

'SIMILAR_TO'

将回写到 Snowflake 数据库的关系类型。

relationshipProperty

字符串

'similarity'

将回写到 Snowflake 数据库的关系属性。

示例

在本节中,我们将展示在具体图表上运行节点相似度算法的示例。目的是说明结果的样子,并为如何在实际环境中使用该算法提供指导。我们将在一个包含少量节点、以特定模式连接的知识图谱上进行演示。示例图如下所示

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 节点。

在此示例中,我们希望使用节点相似度算法,根据人们喜欢的乐器来比较他们。

节点相似度算法将仅计算度数至少为 1 的节点的相似度。在示例图中,Eve 节点将不会与其他人(Person)节点进行比较。

在以下示例中,我们将演示在此图上使用节点相似度算法的过程。

运行作业

运行节点相似度作业涉及三个步骤:投影(Project)、计算(Compute)和写入(Write)。

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

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

以下代码将运行一个节点相似度作业
CALL Neo4j_Graph_Analytics.graph.node_similarity('CPU_X64_XS', {
    'defaultTablePrefix': 'EXAMPLE_DB.DATA_SCHEMA',
    'project': {
        'nodeTables': ['PERSONS', 'INSTRUMENTS'],
        'relationshipTables': {
          'LIKES': {
            'sourceTable': 'PERSONS',
            'targetTable': 'INSTRUMENTS'
          }
        }
    },
    'compute': {
        'resultProperty': 'score',
        'resultRelationshipType': 'SIMILAR'
    },
    'write': [{
        'outputTable': 'PERSONS_SIMILARITY',
        'sourceLabel': 'PERSONS',
        'targetLabel': 'PERSONS',
        'relationshipType': 'SIMILAR',
        'relationshipProperty': 'score'
    }]
});
表 5. 结果
JOB_ID JOB_STATUS JOB_START JOB_END JOB_RESULT

job_36fa8f572b8b412fabb7d9343ed038f8

SUCCESS

2025-06-25 13:30:03.460

2025-06-25 13:30:10.288

 {
    "node_similarity_1": {
      "computeMillis": 60,
      "configuration": {
        "bottomK": 10,
        "bottomN": 0,
        "concurrency": 2,
        "degreeCutoff": 1,
        "nodeLabels": ["*"],
        "relationshipTypes": ["*"],
        "resultProperty": "score",
        "resultRelationshipType": "SIMILAR",
        "similarityCutoff": 1.000000000000000e-42,
        "similarityMetric": "JACCARD",
        "topK": 10,
        "topN": 0,
        "upperDegreeCutoff": 2147483647,
        "useComponents": false
      },
      "nodesCompared": 4,
      "similarityDistribution": {
        "max": 0.6666679382324218,
        "mean": 0.41666641235351565,
        "min": 0.25,
        "p1": 0.25,
        "p10": 0.25,
        "p100": 0.6666660308837891,
        "p25": 0.3333320617675781,
        "p5": 0.25,
        "p50": 0.3333320617675781,
        "p75": 0.5000019073486328,
        "p90": 0.6666660308837891,
        "p95": 0.6666660308837891,
        "p99": 0.6666660308837891,
        "stdDev": 0.14907148283512542
      }
    },
    "project_1": {
      "graphName": "snowgraph",
      "nodeCount": 9,
      "nodeLabels": ...,
      "nodeMillis": 872,
      "relationshipCount": 9,
      "relationshipMillis": 469,
      "relationshipTypes": ...,
      "totalMillis": 1341
    },
    "write_relationship_type_1": {
      "outputTable": "EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY",
      "relationshipProperty": "score",
      "relationshipType": "SIMILAR",
      "rowsWritten": 10,
      "writeMillis": 1917
    }
}

返回的结果包含有关作业执行和结果分布的信息。此外,为已比较节点对计算出的每个相似度得分已写回 Snowflake 数据库。我们可以这样查询它

SELECT * FROM EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY ORDER BY SCORE DESC;

这显示了存储在数据库中的计算结果

表 6. 结果
SOURCENODEID TARGETNODEID SCORE

Alice

Bob

0.6666666667

Bob

Alice

0.6666666667

Alice

Dave

0.5

Dave

Alice

0.5

Alice

Carol

0.3333333333

Carol

Alice

0.3333333333

Carol

Dave

0.3333333333

Dave

Carol

0.3333333333

Bob

Dave

0.25

Dave

Bob

0.25

我们为过程配置参数使用默认值。TopK 设置为 10,topN 设置为 0。因此,结果集包含每个节点的前 10 个相似度得分。

如果我们想改为比较乐器之间的相似性,我们将使用 REVERSE 方向来投影 LIKES 关系类型。这将返回乐器对的相似性,而不会计算人与人之间的任何相似性。

限制结果

可以对相似度结果应用四种限制。Top 将结果限制为最高的相似度得分。Bottom 将结果限制为最低的相似度得分。Top 和 bottom 限制都可以应用于整个结果集("N"),或者应用于每个节点的结果("K")。

必须始终存在一个 "K" 限制(bottomK 或 topK),它必须是一个正数。topK 和 bottomK 的默认值为 10。

表 7. 结果限制
总结果数 每个节点的结果数

最高得分

topN

topK

最低得分

bottomN

bottomK

topK 和 bottomK

TopK 和 bottomK 是对每个节点计算得分数量的限制。对于 topK,返回每个节点得分最高的 K 个相似度得分。对于 bottomK,返回每个节点得分最低的 K 个相似度得分。TopK 和 bottomK 不能为 0,不能同时使用,默认值为 10。如果未指定两者中的任何一个,则使用 topK。

以下代码将运行一个演示 topK 的节点相似度作业
CALL Neo4j_Graph_Analytics.graph.node_similarity('CPU_X64_XS', {
    'defaultTablePrefix': 'EXAMPLE_DB.DATA_SCHEMA',
    'project': {
        'nodeTables': ['PERSONS', 'INSTRUMENTS'],
        'relationshipTables': {
          'LIKES': {
            'sourceTable': 'PERSONS',
            'targetTable': 'INSTRUMENTS'
          }
        }
    },
    'compute': {
        'resultProperty': 'score',
        'resultRelationshipType': 'SIMILAR',
        'topK': 1
    },
    'write': [{
        'outputTable': 'PERSONS_SIMILARITY',
        'sourceLabel': 'PERSONS',
        'targetLabel': 'PERSONS',
        'relationshipType': 'SIMILAR',
        'relationshipProperty': 'score'
    }]
});
表 8. 结果
JOB_ID JOB_STATUS JOB_START JOB_END JOB_RESULT

job_c87ccfc6c46742548940fff74eeeeea6

SUCCESS

2025-06-25 13:47:42.029

2025-06-25 13:47:47.708

 {
    "node_similarity_1": {
      "computeMillis": 33,
      "configuration": {
        "bottomK": 10,
        "bottomN": 0,
        "concurrency": 2,
        "degreeCutoff": 1,
        "nodeLabels": ["*"],
        "relationshipTypes": ["*"],
        "resultProperty": "score",
        "resultRelationshipType": "SIMILAR",
        "similarityCutoff": 1.000000000000000e-42,
        "similarityMetric": "JACCARD",
        "topK": 1,
        "topN": 0,
        "upperDegreeCutoff": 2147483647,
        "useComponents": false
      },
      "nodesCompared": 4,
      "similarityDistribution": {
        "max": 0.6666679382324218,
        "mean": 0.5416665077209473,
        "min": 0.3333320617675781,
        "p1": 0.3333320617675781,
        "p10": 0.3333320617675781,
        "p100": 0.6666660308837891,
        "p25": 0.3333320617675781,
        "p5": 0.3333320617675781,
        "p50": 0.5000019073486328,
        "p75": 0.6666660308837891,
        "p90": 0.6666660308837891,
        "p95": 0.6666660308837891,
        "p99": 0.6666660308837891,
        "stdDev": 0.13819274752746397
      }
    },
    "project_1": {
      "graphName": "snowgraph",
      "nodeCount": 9,
      "nodeLabels": ...,
      "nodeMillis": 218,
      "relationshipCount": 9,
      "relationshipMillis": 322,
      "relationshipTypes": ...,
      "totalMillis": 540
    },
    "write_relationship_type_1": {
      "outputTable": "EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY",
      "relationshipProperty": "score",
      "relationshipType": "SIMILAR",
      "rowsWritten": 4,
      "writeMillis": 1958
    }
}
SELECT * FROM EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY ORDER BY SCORE DESC;
表 9. 结果
SOURCENODEID TARGETNODEID SCORE

Alice

Bob

0.6666666667

Bob

Alice

0.6666666667

Dave

Alice

0.5

Carol

Alice

0.3333333333

以下是如何使用 bottomK 的示例

以下代码将运行一个演示 bottomK 的节点相似度作业
CALL Neo4j_Graph_Analytics.graph.node_similarity('CPU_X64_XS', {
    'defaultTablePrefix': 'EXAMPLE_DB.DATA_SCHEMA',
    'project': {
        'nodeTables': ['PERSONS', 'INSTRUMENTS'],
        'relationshipTables': {
          'LIKES': {
            'sourceTable': 'PERSONS',
            'targetTable': 'INSTRUMENTS'
          }
        }
    },
    'compute': {
        'resultProperty': 'score',
        'resultRelationshipType': 'SIMILAR',
        'bottomK': 1
    },
    'write': [{
        'outputTable': 'PERSONS_SIMILARITY',
        'sourceLabel': 'PERSONS',
        'targetLabel': 'PERSONS',
        'relationshipType': 'SIMILAR',
        'relationshipProperty': 'score'
    }]
});
表 10. 结果
JOB_ID JOB_STATUS JOB_START JOB_END JOB_RESULT

job_2fdc12517bc54905906e2f2eb396d00b

SUCCESS

2025-06-25 14:14:47.657

2025-06-25 14:14:53.313

 {
    "node_similarity_1": {
      "computeMillis": 25,
      "configuration": {
        "bottomK": 1,
        "bottomN": 0,
        "concurrency": 2,
        "degreeCutoff": 1,
        "nodeLabels": ["*"],
        "relationshipTypes": ["*"],
        "resultProperty": "score",
        "resultRelationshipType": "SIMILAR",
        "similarityCutoff": 1.000000000000000e-42,
        "similarityMetric": "JACCARD",
        "topK": 10,
        "topN": 0,
        "upperDegreeCutoff": 2147483647,
        "useComponents": false
      },
      "nodesCompared": 4,
      "similarityDistribution": {
        "max": 0.3333339691162109,
        "mean": 0.29166603088378906,
        "min": 0.25,
        "p1": 0.25,
        "p10": 0.25,
        "p100": 0.3333320617675781,
        "p25": 0.25,
        "p5": 0.25,
        "p50": 0.25,
        "p75": 0.3333320617675781,
        "p90": 0.3333320617675781,
        "p95": 0.3333320617675781,
        "p99": 0.3333320617675781,
        "stdDev": 0.04166603088378906
      }
    },
    "project_1": {
      "graphName": "snowgraph",
      "nodeCount": 9,
      "nodeLabels": ...,
      "nodeMillis": 188,
      "relationshipCount": 9,
      "relationshipMillis": 369,
      "relationshipTypes": ...,
      "totalMillis": 557
    },
    "write_relationship_type_1": {
      "outputTable": "EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY",
      "relationshipProperty": "score",
      "relationshipType": "SIMILAR",
      "rowsWritten": 4,
      "writeMillis": 2105
    }
}
SELECT * FROM EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY ORDER BY SCORE DESC;
表 11. 结果
SOURCENODEID TARGETNODEID SCORE

Alice

Carol

0.3333333333

Carol

Alice

0.3333333333

Bob

Dave

0.25

Dave

Bob

0.25

topN 和 bottomN

TopN 和 bottomN 限制了所有节点上的相似度得分数量。这是对总结果集的限制,是对每个节点 topK 或 bottomK 限制的补充。对于 topN,返回 N 个最高的相似度得分。对于 bottomN,返回 N 个最低的相似度得分。值为 0 表示不施加全局限制,并返回 topK 或 bottomK 的所有结果。

以下代码将运行该算法,并流式传输每个节点 top 1 结果中的前 3 个最高得分
CALL Neo4j_Graph_Analytics.graph.node_similarity('CPU_X64_XS', {
    'defaultTablePrefix': 'EXAMPLE_DB.DATA_SCHEMA',
    'project': {
        'nodeTables': ['PERSONS', 'INSTRUMENTS'],
        'relationshipTables': {
          'LIKES': {
            'sourceTable': 'PERSONS',
            'targetTable': 'INSTRUMENTS'
          }
        }
    },
    'compute': {
        'resultProperty': 'score',
        'resultRelationshipType': 'SIMILAR',
        'topK': 1,
        'topN': 3
    },
    'write': [{
        'outputTable': 'PERSONS_SIMILARITY',
        'sourceLabel': 'PERSONS',
        'targetLabel': 'PERSONS',
        'relationshipType': 'SIMILAR',
        'relationshipProperty': 'score'
    }]
});
表 12. 结果
JOB_ID JOB_STATUS JOB_START JOB_END JOB_RESULT

job_ab183c8a38e64d23936b61781cebe2e7

SUCCESS

2025-06-26 07:15:15.951

2025-06-26 07:15:22.810

 {
    "node_similarity_1": {
      "computeMillis": 45,
      "configuration": {
        "bottomK": 10,
        "bottomN": 0,
        "concurrency": 2,
        "degreeCutoff": 1,
        "nodeLabels": ["*"],
        "relationshipTypes": ["*"],
        "resultProperty": "score",
        "resultRelationshipType": "SIMILAR",
        "similarityCutoff": 1.000000000000000e-42,
        "similarityMetric": "JACCARD",
        "topK": 1,
        "topN": 3,
        "upperDegreeCutoff": 2147483647,
        "useComponents": false
      },
      "nodesCompared": 4,
      "similarityDistribution": {
        "max": 0.6666679382324218,
        "mean": 0.6111094156901041,
        "min": 0.5,
        "p1": 0.5,
        "p10": 0.5,
        "p100": 0.6666641235351562,
        "p25": 0.5,
        "p5": 0.5,
        "p50": 0.6666641235351562,
        "p75": 0.6666641235351562,
        "p90": 0.6666641235351562,
        "p95": 0.6666641235351562,
        "p99": 0.6666641235351562,
        "stdDev": 0.07856622128814764
      }
    },
    "project_1": {
      "graphName": "snowgraph",
      "nodeCount": 9,
      "nodeLabels": ...,
      "nodeMillis": 914,
      "relationshipCount": 9,
      "relationshipMillis": 662,
      "relationshipTypes": ...,
      "totalMillis": 1576
    },
    "write_relationship_type_1": {
      "outputTable": "EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY",
      "relationshipProperty": "score",
      "relationshipType": "SIMILAR",
      "rowsWritten": 3,
      "writeMillis": 2113
    }
}
SELECT * FROM EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY ORDER BY SCORE DESC;
表 13. 结果
SOURCENODEID TARGETNODEID SCORE

Alice

Bob

0.6666666667

Bob

Alice

0.6666666667

Dave

Alice

0.5

度数截断和相似度截断

可以通过两个名为 degreeCutoffupperDegreeCutoff 的整数参数来调整节点相似度,以基于度数约束忽略某些节点。如果设置了 degreeCutoff,它会对度数施加下限,只有度数高于此值的节点才会被考虑在比较中,并跳过任何度数低于 degreeCutoff 的节点。如果设置了 upperDegreeCutoff,它会对节点度数施加上限,并跳过任何度数高于 upperDegreeCutoff 的节点。这两个参数也可以组合使用,以便只考虑度数落入特定区间的节点。

两个参数的最小值为 1

以下代码将运行该算法,并计算每个节点 top 1 结果中的前 3 个最高得分
CALL Neo4j_Graph_Analytics.graph.node_similarity('CPU_X64_XS', {
    'defaultTablePrefix': 'EXAMPLE_DB.DATA_SCHEMA',
    'project': {
        'nodeTables': ['PERSONS', 'INSTRUMENTS'],
        'relationshipTables': {
          'LIKES': {
            'sourceTable': 'PERSONS',
            'targetTable': 'INSTRUMENTS'
          }
        }
    },
    'compute': {
        'resultProperty': 'score',
        'resultRelationshipType': 'SIMILAR',
        'degreeCutoff': 3
    },
    'write': [{
        'outputTable': 'PERSONS_SIMILARITY',
        'sourceLabel': 'PERSONS',
        'targetLabel': 'PERSONS',
        'relationshipType': 'SIMILAR',
        'relationshipProperty': 'score'
    }]
});
表 14. 结果
JOB_ID JOB_STATUS JOB_START JOB_END JOB_RESULT

job_3687173082d14993a228eab0663ff557

SUCCESS

2025-06-26 08:14:43.945

2025-06-26 08:14:49.441

 {
    "node_similarity_1": {
      "computeMillis": 23,
      "configuration": {
        "bottomK": 10,
        "bottomN": 0,
        "concurrency": 2,
        "degreeCutoff": 3,
        "nodeLabels": ["*"],
        "relationshipTypes": ["*"],
        "resultProperty": "score",
        "resultRelationshipType": "SIMILAR",
        "similarityCutoff": 1.000000000000000e-42,
        "similarityMetric": "JACCARD",
        "topK": 10,
        "topN": 0,
        "upperDegreeCutoff": 2147483647,
        "useComponents": false
      },
      "nodesCompared": 2,
      "similarityDistribution": {
        "max": 0.5000038146972655,
        "mean": 0.5,
        "min": 0.5,
        "p1": 0.5,
        "p10": 0.5,
        "p100": 0.5,
        "p25": 0.5,
        "p5": 0.5,
        "p50": 0.5,
        "p75": 0.5,
        "p90": 0.5,
        "p95": 0.5,
        "p99": 0.5,
        "stdDev": 0
      }
    },
    "project_1": {
      "graphName": "snowgraph",
      "nodeCount": 9,
      "nodeLabels": ...,
      "nodeMillis": 227,
      "relationshipCount": 9,
      "relationshipMillis": 426,
      "relationshipTypes": ...,
      "totalMillis": 653
    },
    "write_relationship_type_1": {
      "outputTable": "EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY",
      "relationshipProperty": "score",
      "relationshipType": "SIMILAR",
      "rowsWritten": 2,
      "writeMillis": 1931
    }
}
SELECT * FROM EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY ORDER BY SCORE DESC;
表 15. 结果
SOURCENODEID TARGETNODEID SCORE

Alice

Dave

0.5

Dave

Alice

0.5

相似度截断(Similarity cutoff)是结果中包含的相似度得分的下限。默认值非常小 (1E-42),用于排除相似度得分为 0 的结果。

将相似度截断设置为 0 可能会产生非常大的结果集,并增加运行时间和内存消耗。

以下代码将忽略相似度得分低于 0.5 的节点对
CALL Neo4j_Graph_Analytics.graph.node_similarity('CPU_X64_XS', {
    'defaultTablePrefix': 'EXAMPLE_DB.DATA_SCHEMA',
    'project': {
        'nodeTables': ['PERSONS', 'INSTRUMENTS'],
        'relationshipTables': {
          'LIKES': {
            'sourceTable': 'PERSONS',
            'targetTable': 'INSTRUMENTS'
          }
        }
    },
    'compute': {
        'resultProperty': 'score',
        'resultRelationshipType': 'SIMILAR',
        'similarityCutoff': 0.5
    },
    'write': [{
        'outputTable': 'PERSONS_SIMILARITY',
        'sourceLabel': 'PERSONS',
        'targetLabel': 'PERSONS',
        'relationshipType': 'SIMILAR',
        'relationshipProperty': 'score'
    }]
});
表 16. 结果
JOB_ID JOB_STATUS JOB_START JOB_END JOB_RESULT

job_5f6827d7e57949209a48a876875ab65b

SUCCESS

2025-06-26 09:45:59.862

2025-06-26 09:46:05.996

 {
    "node_similarity_1": {
      "computeMillis": 28,
      "configuration": {
        "bottomK": 10,
        "bottomN": 0,
        "concurrency": 2,
        "degreeCutoff": 1,
        "nodeLabels": ["*"],
        "relationshipTypes": ["*"],
        "resultProperty": "score",
        "resultRelationshipType": "SIMILAR",
        "similarityCutoff": 0.5,
        "similarityMetric": "JACCARD",
        "topK": 10,
        "topN": 0,
        "upperDegreeCutoff": 2147483647,
        "useComponents": false
      },
      "nodesCompared": 4,
      "similarityDistribution": {
        "max": 0.6666679382324218,
        "mean": 0.5833320617675781,
        "min": 0.5,
        "p1": 0.5,
        "p10": 0.5,
        "p100": 0.6666641235351562,
        "p25": 0.5,
        "p5": 0.5,
        "p50": 0.5,
        "p75": 0.6666641235351562,
        "p90": 0.6666641235351562,
        "p95": 0.6666641235351562,
        "p99": 0.6666641235351562,
        "stdDev": 0.08333206176757812
      }
    },
    "project_1": {
      "graphName": "snowgraph",
      "nodeCount": 9,
      "nodeLabels": ...,
      "nodeMillis": 340,
      "relationshipCount": 9,
      "relationshipMillis": 522,
      "relationshipTypes": ...,
      "totalMillis": 862
    },
    "write_relationship_type_1": {
      "outputTable": "EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY",
      "relationshipProperty": "score",
      "relationshipType": "SIMILAR",
      "rowsWritten": 4,
      "writeMillis": 2245
    }
}
SELECT * FROM EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY ORDER BY SCORE DESC;
表 17. 结果
SOURCENODEID TARGETNODEID SCORE

Alice

Bob

0.6666666667

Bob

Alice

0.6666666667

Alice

Dave

0.5

Dave

Alice

0.5

加权相似度

关系属性可用于通过将其值作为衡量重要性的方式,来修改由特定关系诱导的相似度。默认情况下,加权节点相似度使用加权 Jaccard 相似度,公式如下

weighted jaccard

从形式上讲,给定两个节点及其加权邻居列表 A'B',我们将列表扩展为 AB,通过为任何非邻居设置权重 = 0,在它们的邻居并集 A' ∪ B' 上建立索引,然后应用加权 Jaccard 相似度。

它还支持加权 Overlap 相似度,公式如下

weighted overlap

此外,正如简介中提到的,余弦相似度也可以用于加权情况。

加权相似度指标仅针对大于或等于 0 的值定义。

以下查询将在相似度计算中考虑关系属性
CALL Neo4j_Graph_Analytics.graph.node_similarity('CPU_X64_XS', {
    'defaultTablePrefix': 'EXAMPLE_DB.DATA_SCHEMA',
    'project': {
        'nodeTables': ['PERSONS', 'INSTRUMENTS'],
        'relationshipTables': {
          'LIKES': {
            'sourceTable': 'PERSONS',
            'targetTable': 'INSTRUMENTS'
          }
        }
    },
    'compute': {
        'resultProperty': 'score',
        'resultRelationshipType': 'SIMILAR',
        'relationshipWeightProperty': 'WEIGHT',
        'similarityCutoff': 0.3
    },
    'write': [{
        'outputTable': 'PERSONS_SIMILARITY',
        'sourceLabel': 'PERSONS',
        'targetLabel': 'PERSONS',
        'relationshipType': 'SIMILAR',
        'relationshipProperty': 'score'
    }]
});
表 18. 结果
JOB_ID JOB_STATUS JOB_START JOB_END JOB_RESULT

job_532fbaf2ca3345168509c103dab5a419

SUCCESS

2025-07-02 08:18:07.452

2025-07-02 08:18:13.844

 {
    "node_similarity_1": {
      "computeMillis": 25,
      "configuration": {
        "bottomK": 10,
        "bottomN": 0,
        "concurrency": 2,
        "degreeCutoff": 1,
        "nodeLabels": ["*"],
        "relationshipTypes": ["*"],
        "relationshipWeightProperty": "WEIGHT",
        "resultProperty": "score",
        "resultRelationshipType": "SIMILAR",
        "similarityCutoff": 0.3,
        "similarityMetric": "JACCARD",
        "topK": 10,
        "topN": 0,
        "upperDegreeCutoff": 2147483647,
        "useComponents": false
      },
      "nodesCompared": 4,
      "similarityDistribution": {
        "max": 0.8000030517578124,
        "mean": 0.5666666030883789,
        "min": 0.3333320617675781,
        "p1": 0.3333320617675781,
        "p10": 0.3333320617675781,
        "p100": 0.8000011444091797,
        "p25": 0.3333320617675781,
        "p5": 0.3333320617675781,
        "p50": 0.3333320617675781,
        "p75": 0.8000011444091797,
        "p90": 0.8000011444091797,
        "p95": 0.8000011444091797,
        "p99": 0.8000011444091797,
        "stdDev": 0.23333454132080078
      }
    },
    "project_1": {
      "graphName": "snowgraph",
      "nodeCount": 9,
      "nodeLabels": ...,
      "nodeMillis": 640,
      "relationshipCount": 9,
      "relationshipMillis": 719,
      "relationshipTypes": ...,
      "totalMillis": 1359
    },
    "write_relationship_type_1": {
      "outputTable": "EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY",
      "relationshipProperty": "score",
      "relationshipType": "SIMILAR",
      "rowsWritten": 4,
      "writeMillis": 1973
    }
}
SELECT * FROM EXAMPLE_DB.DATA_SCHEMA.PERSONS_SIMILARITY ORDER BY SCORE DESC;
表 19. 结果
SOURCENODEID TARGETNODEID SCORE

Alice

Bob

0.8

Alice

Dave

0.3333333333

Bob

Alice

0.8

Dave

Alice

0.3333333333

可以看到,与该算法的非加权版本相比,Alice 和 Dave 之间的相似度降低了(从 0.5 降至 0.33)。

Alice 喜欢吉他、合成器和邦戈鼓,强度为 (1, 1, 0.5)。Dave 喜欢吉他、邦戈鼓和喇叭,强度为 (1, 1, 1.5)。因此,取 Alice 和 Dave 的邻居,我们得到 Alice 的强度列表为 A = (1, 1, 0.5, 0),Dave 的为 B = (1, 0, 1, 1.5),按 吉他、合成器、邦戈鼓、喇叭 索引。

因此,Alice 和 Dave 的加权(Jaccard)节点相似度为

weighted jaccard example

类似地,Alice 和 Bob 之间的相似度增加了(从 0.66 增至 0.8),因为缺失的喜欢的乐器对相似度得分的影响较小。