跳转至
开发版采用单机部署,无需产品 License 文件。需要多机部署或大规模性能测试? 了解企业版

余弦相似度

本文介绍余弦相似度算法,并演示如何用 GQL 实现该算法。

算法介绍

余弦相似度通过向量夹角衡量点或对象之间的相似程度。

该过程将算法逻辑封装为可复用过程,可直接在图数据上执行并输出结果。

更多信息,请参见余弦相似度。

数据模型

为了在 GQL 中实现余弦相似度算法,使用以下数据模型创建图类型:

  • 实体由类型为Node的点表示,点属性包括id和rating。
  • 实体间关系由类型为Link的边表示,边属性包括weight。

该图类型的完整定义,请参见准备图数据。

过程实现

为了计算余弦相似度结果,创建一个过程。

关于该过程的更多信息,请参见过程实现。下文将介绍该过程的关键组成部分及其工作原理。

该过程接受以下输入参数:

  • left_id:INT64类型。 第一个待比较点的 ID。
  • right_id:INT64类型。 第二个待比较点的 ID。

此外,在过程内部定义了以下变量:

变量名 变量类型 描述
common_cnt 全局 SumAgg 聚合值变量 左右点之间的共同邻居数量。
left_deg 全局 SumAgg 聚合值变量 左侧查询点的度数。
right_deg 全局 SumAgg 聚合值变量 右侧查询点的度数。
dot_val 全局 SumAgg 聚合值变量 左右点邻域指示向量的点积。
left_norm_sq 全局 SumAgg 聚合值变量 左点邻域向量的 L2 范数的平方。
right_norm_sq 全局 SumAgg 聚合值变量 右点邻域向量的 L2 范数的平方。
similarity 原始值变量 两点之间的最终余弦相似度分数。
left_cnt 点绑定 SumAgg 聚合值变量 每点标志/计数,表示该点是否在左点的邻域内。
right_cnt 点绑定 SumAgg 聚合值变量 每点标志/计数,表示该点是否在右点的邻域内。

以下步骤概述了该过程的逻辑:

  1. 对左侧点,将其所有邻居标记为seen_left;对右侧点,将其所有邻居标记为seen_right。
  2. 计算dot_val(共同邻居数)、left_norm_sq(左点度数)和right_norm_sq(右点度数)。
  3. 按公式dot_val / sqrt(left_norm_sq × right_norm_sq)计算余弦相似度。
  4. 返回相似度分数。

操作步骤

在悦数图管理的控制台中,按顺序执行以下代码块。首次使用时,先按准备算法示例数据确认操作位置和目录挂载。

1. 准备图数据

  1. 创建一个与数据模型匹配的图类型。

    '''
    CREATE GRAPH TYPE IF NOT EXISTS cosine_similarity_graph_type AS {
        NODE Node (LABEL Node {id INT PRIMARY KEY, rating INT}),
        EDGE Link (Node)-[LABEL Link {weight INT, MULTIEDGE KEY()}]->(Node)
    }
    '''
    
  2. 下载以下 CSV 文件,保留文件名,保存到部署目录下的examples/algorithms/cosine_similarity/:

    查看 CSV 内容
    cosine_similarity_node.csv
    id,rating
    1,0
    2,2
    3,1
    4,0
    5,0
    6,2
    7,1
    8,2
    9,0
    10,1
    11,0
    12,2
    13,1
    14,1
    15,0
    16,2
    17,0
    18,1
    19,2
    20,0
    21,2
    22,1
    23,0
    24,1
    
    cosine_similarity_edge.csv
    src_id,dst_id,weight
    1,2,4
    1,3,2
    1,4,7
    1,5,9
    2,3,1
    2,4,6
    2,5,5
    2,6,2
    3,4,3
    3,5,4
    3,6,8
    4,6,2
    4,7,6
    4,8,5
    5,6,4
    5,8,7
    5,9,6
    6,8,1
    6,9,5
    6,10,6
    7,9,2
    7,10,9
    8,9,3
    8,11,6
    8,12,4
    9,10,4
    9,12,7
    9,13,2
    10,12,1
    10,13,8
    10,14,4
    11,12,2
    11,14,5
    11,15,7
    12,14,3
    12,15,6
    12,16,5
    13,15,2
    13,16,7
    14,15,4
    14,17,8
    14,18,2
    15,16,1
    15,18,5
    15,19,3
    16,18,3
    16,19,6
    17,18,2
    17,20,7
    17,21,5
    18,19,4
    18,21,9
    18,22,6
    19,21,1
    19,22,5
    20,21,3
    20,23,6
    20,24,8
    21,22,2
    21,23,4
    21,24,7
    22,24,4
    23,24,1
    
  3. 基于图类型创建临时图,并将数据文件加载到临时图中。

    CREATE TEMPORARY GRAPH IF NOT EXISTS #cosine_similarity_graph TYPED cosine_similarity_graph_type
    
    '''
    USE #cosine_similarity_graph IMPORT INTO GRAPH {
          NODE (v@Node {id: id, rating: rating}) FROM DATAFILE {
              PATH: "file:///examples/algorithms/cosine_similarity/cosine_similarity_node.csv",
              FORMAT: "CSV",
              DELIMITER: ','
          },
          EDGE (id: src_id)-[e@Link {weight: weight}]->(id: dst_id) FROM DATAFILE {
              PATH: "file:///examples/algorithms/cosine_similarity/cosine_similarity_edge.csv",
              FORMAT: "CSV",
              DELIMITER: ','
          }
      }
    '''
    

    导入成功后,在控制台执行以下查询核对点数:

    '''
    USE #cosine_similarity_graph
    MATCH (n)
    RETURN count(n) AS node_count
    '''
    

    node_count应为24。点数不符时,先按文件问题排查检查文件和导入结果。

2. 创建过程

创建实现余弦相似度算法的过程。关于该过程的更多信息,请参见过程实现。

'''
CREATE OR REPLACE PROCEDURE cosine_similarity_score(left_id INT64, right_id INT64)
RETURNS (
  query_left_id INT64,
  query_right_id INT64,
  left_degree INT64,
  right_degree INT64,
  common_neighbor_count INT64,
  dot_product DOUBLE,
  score DOUBLE
)
COMMENT "Compute cosine similarity between two vertices identified by vertex property id using undirected 1-hop neighborhoods, counting parallel edges as multiplicity in the adjacency vector."
AS {
  VALUE common_cnt SumAgg<INT64> = 0
  VALUE left_deg SumAgg<INT64> = 0
  VALUE right_deg SumAgg<INT64> = 0
  VALUE dot_val SumAgg<DOUBLE> = 0.0
  VALUE left_norm_sq SumAgg<DOUBLE> = 0.0
  VALUE right_norm_sq SumAgg<DOUBLE> = 0.0
  VALUE similarity DOUBLE = 0.0

  NODE VALUE left_cnt SumAgg<INT64> = 0
  NODE VALUE right_cnt SumAgg<INT64> = 0

  MATCH (s)-[e]-(n)
  WHERE s.id = left_id
  PER PATH {
    SET n.@left_cnt += 1
  }

  MATCH (s)-[e]-(n)
  WHERE s.id = right_id
  PER PATH {
    SET n.@right_cnt += 1
  }

  MATCH (n)
  WHERE n.@left_cnt > 0
  PER NODE (n) {
    SET @left_deg += n.@left_cnt
    SET @left_norm_sq += CAST(n.@left_cnt AS DOUBLE) * CAST(n.@left_cnt AS DOUBLE)
  }

  MATCH (n)
  WHERE n.@right_cnt > 0
  PER NODE (n) {
    SET @right_deg += n.@right_cnt
    SET @right_norm_sq += CAST(n.@right_cnt AS DOUBLE) * CAST(n.@right_cnt AS DOUBLE)
  }

  MATCH (n)
  WHERE n.@left_cnt > 0
    AND n.@right_cnt > 0
    AND n.id <> left_id
    AND n.id <> right_id
  PER NODE (n) {
    SET @common_cnt += 1
    SET @dot_val += CAST(n.@left_cnt AS DOUBLE) * CAST(n.@right_cnt AS DOUBLE)
  }

  IF left_id = right_id THEN {
    SET similarity = 1.0
  }
  ELSEIF @left_deg = 0 OR @right_deg = 0 THEN {
    SET similarity = 0.0
  }
  ELSE {
    SET similarity = @dot_val / sqrt(@left_norm_sq * @right_norm_sq)
  }

  RETURN
    left_id AS query_left_id,
    right_id AS query_right_id,
    @left_deg AS left_degree,
    @right_deg AS right_degree,
    @common_cnt AS common_neighbor_count,
    @dot_val AS dot_product,
    similarity AS score
}
'''

3. 调用过程

计算点6和点9的余弦相似度。

USE #cosine_similarity_graph CALL cosine_similarity_score(6, 9) RETURN query_left_id, query_right_id, left_degree, right_degree, common_neighbor_count, dot_product, score

返回:

+---------------+----------------+-------------+--------------+-----------------------+-------------+---------------------+
| query_left_id | query_right_id | left_degree | right_degree | common_neighbor_count | dot_product | score               |
+---------------+----------------+-------------+--------------+-----------------------+-------------+---------------------+
| 6             | 9              | 7           | 7            | 3                     | 3.0         | 0.42857142857142855 |
+---------------+----------------+-------------+--------------+-----------------------+-------------+---------------------+
保存结果到文件或图中

如需将返回的结果保存为 CSV 文件或写入图,请参见 EXPORT。导出字段应与返回列及目标属性对应。