Cosine Similarity¶
Algorithm introduction¶
Cosine similarity computes pairwise similarity scores from vector directions in embedding space.
Compute cosine similarity between two nodes identified by node property id using undirected 1-hop neighborhoods, counting parallel edges as multiplicity in the adjacency vector.
For more information, see Cosine Similarity.
Data model¶
To implement the Cosine Similarity algorithm in GQL, the following data model is used to create a graph type:
- Entities are represented by nodes of type
Node, with propertiesidandrating. - Relationships are represented by edges of type
Link, with propertyweight.
For the complete definition of the graph type, see Prepare graph data.
Procedure implementation¶
To compute Cosine Similarity results, a procedure is created.
For more information about the procedure, see Procedure implementation. The following section describes the key components of the procedure and how it works.
The procedure takes the following input parameters:
left_id:INT64. ID of the first node to compare.right_id:INT64. ID of the second node to compare.
Additionally, the following variables are defined within the procedure:
| Variable name | Variable type | Description |
|---|---|---|
common_cnt |
Global SumAgg aggregator value variable | Count of common neighbors between the left and right nodes. |
left_deg |
Global SumAgg aggregator value variable | Degree of the left query node. |
right_deg |
Global SumAgg aggregator value variable | Degree of the right query node. |
dot_val |
Global SumAgg aggregator value variable | Dot product of left and right node neighborhood indicator vectors. |
left_norm_sq |
Global SumAgg aggregator value variable | Squared L2 norm of the left node's neighborhood vector. |
right_norm_sq |
Global SumAgg aggregator value variable | Squared L2 norm of the right node's neighborhood vector. |
similarity |
Primitive value variable | Final cosine similarity score between the two nodes. |
left_cnt |
Node-attached SumAgg aggregator value variable | Per-node flag/count indicating membership in left node's neighborhood. |
right_cnt |
Node-attached SumAgg aggregator value variable | Per-node flag/count indicating membership in right node's neighborhood. |
The following steps outline the logic of the procedure:
- For the left node, mark all its neighbors with
seen_left; for the right node, mark all withseen_right. - Compute
dot_val(number of common neighbors),left_norm_sq(left node degree), andright_norm_sq(right node degree). - Compute cosine similarity as
dot_val / sqrt(left_norm_sq × right_norm_sq). - Return the similarity score.
Steps¶
Run the following code blocks in order in the NebulaGraph Studio CONSOLE. For first-time setup, follow Prepare algorithm sample data to check where to run commands and how the directory is mounted.
1. Prepare graph data¶
-
Create a graph type that matches your data model.
''' 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) } ''' -
Download these CSV files and save them with their original names in
examples/algorithms/cosine_similarity/under your deployment directory:- cosine_similarity_node.csv: Node data.
- cosine_similarity_edge.csv: Edge data.
Preview the CSV files
cosine_similarity_node.csvid,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,1cosine_similarity_edge.csvsrc_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 -
Create a temporary graph based on the graph type and load the data files into the temporary graph.
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: ',' } } '''After the import succeeds, run this query in the console to check the node count:
''' USE #cosine_similarity_graph MATCH (n) RETURN count(n) AS node_count '''The expected
node_countis24. If it differs, check the files and import results before continuing.
2. Create a procedure¶
Create a procedure to implement the Cosine Similarity algorithm. For more information about the procedure, see Procedure implementation.
'''
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. Call your procedure¶
Compute cosine similarity between nodes 6 and 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
Returns:
+---------------+----------------+-------------+--------------+-----------------------+-------------+---------------------+
| 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 |
+---------------+----------------+-------------+--------------+-----------------------+-------------+---------------------+
Save results to a file or graph
To save the returned results as CSV files or write them to a graph, see EXPORT. Match the exported fields to the returned columns and target properties.