Source: https://dev-docs.yueshu.com.cn/v5.3.2/analytic/algorithms/cosine_similarity/ Documentation version: v5.3.2 # 余弦相似度 本文介绍余弦相似度算法,并演示如何用 GQL 实现该算法。 ## 算法介绍 余弦相似度通过向量夹角衡量点或对象之间的相似程度。 该过程将算法逻辑封装为可复用过程,可直接在图数据上执行并输出结果。 更多信息,请参见[余弦相似度](https://zh.wikipedia.org/wiki/%E4%BD%99%E5%BC%A6%E7%9B%B8%E4%BC%BC%E6%80%A7)。 ## 数据模型 为了在 GQL 中实现余弦相似度算法,使用以下数据模型创建图类型: - 实体由类型为`Node`的点表示,点属性包括`id`和`rating`。 - 实体间关系由类型为`Link`的边表示,边属性包括`weight`。 该图类型的完整定义,请参见[准备图数据](https://dev-docs.yueshu.com.cn/v5.3.2/analytic/algorithms/cosine_similarity/#1_prepare_graph_data)。 ## 过程实现[]() 为了计算余弦相似度结果,创建一个[过程](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/procedures/create/)。 关于该过程的更多信息,请参见[过程实现](https://dev-docs.yueshu.com.cn/v5.3.2/analytic/algorithms/cosine_similarity/#procedure_implement)。下文将介绍该过程的关键组成部分及其工作原理。 该过程接受以下输入参数: - `left_id`:`INT64`类型。 第一个待比较点的 ID。 - `right_id`:`INT64`类型。 第二个待比较点的 ID。 此外,在过程内部定义了以下变量: | 变量名 | 变量类型 | 描述 | `common_cnt` | 全局 [SumAgg 聚合值变量](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | 左右点之间的共同邻居数量。 | `left_deg` | 全局 [SumAgg 聚合值变量](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | 左侧查询点的度数。 | `right_deg` | 全局 [SumAgg 聚合值变量](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | 右侧查询点的度数。 | `dot_val` | 全局 [SumAgg 聚合值变量](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | 左右点邻域指示向量的点积。 | `left_norm_sq` | 全局 [SumAgg 聚合值变量](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | 左点邻域向量的 L2 范数的平方。 | `right_norm_sq` | 全局 [SumAgg 聚合值变量](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | 右点邻域向量的 L2 范数的平方。 | `similarity` | [原始值变量](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/variable-definition/value-variable/) | 两点之间的最终余弦相似度分数。 | `left_cnt` | 点绑定 [SumAgg 聚合值变量](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | 每点标志/计数,表示该点是否在左点的邻域内。 | `right_cnt` | 点绑定 [SumAgg 聚合值变量](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | 每点标志/计数,表示该点是否在右点的邻域内。 以下步骤概述了该过程的逻辑: 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. 返回相似度分数。 ## 操作步骤 在悦数图管理的控制台中,按顺序执行以下代码块。首次使用时,先按[准备算法示例数据](https://dev-docs.yueshu.com.cn/v5.3.2/analytic/algorithms/prepare-data/)确认操作位置和目录挂载。 ### 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/`: - [cosine_similarity_node.csv](https://dev-docs.yueshu.com.cn/v5.3.2/analytic/algorithms/files/cosine_similarity/cosine_similarity_node.csv):点数据。 - [cosine_similarity_edge.csv](https://dev-docs.yueshu.com.cn/v5.3.2/analytic/algorithms/files/cosine_similarity/cosine_similarity_edge.csv):边数据。 查看 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`。点数不符时,先按[文件问题排查](https://dev-docs.yueshu.com.cn/v5.3.2/analytic/algorithms/prepare-data/#troubleshooting)检查文件和导入结果。 ### 2. 创建过程[]() 创建实现余弦相似度算法的过程。关于该过程的更多信息,请参见[过程实现](https://dev-docs.yueshu.com.cn/v5.3.2/analytic/algorithms/cosine_similarity/#procedure_implement)。 ```` ''' 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 = 0 VALUE left_deg SumAgg = 0 VALUE right_deg SumAgg = 0 VALUE dot_val SumAgg = 0.0 VALUE left_norm_sq SumAgg = 0.0 VALUE right_norm_sq SumAgg = 0.0 VALUE similarity DOUBLE = 0.0 NODE VALUE left_cnt SumAgg = 0 NODE VALUE right_cnt SumAgg = 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](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/in-out/export/)。导出字段应与返回列及目标属性对应。