Source: https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/adamic_adar/ Documentation version: v5.3.2 # Adamic-Adar ## Algorithm introduction Adamic-Adar uses common neighbors to determine how likely two nodes are to connect. The score is higher when the nodes share more common neighbors, especially when those neighbors are connected to fewer other nodes. Compute the Adamic-Adar score between two nodes identified by node property id. For more information, see [Adamic-Adar](https://en.wikipedia.org/wiki/Adamic%E2%80%93Adar_index). ## Data model To implement the Adamic-Adar algorithm in GQL, the following data model is used to create a graph type: - Entities are represented by nodes of type `Node`, with properties `id` and `rating`. - Relationships are represented by edges of type `Link`, with property `weight`. For the complete definition of the graph type, see [Prepare graph data](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/adamic_adar/#1_prepare_graph_data). ## Procedure implementation[]() To compute Adamic-Adar results, a [procedure](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/procedures/create/) is created. For more information about the procedure, see [Procedure implementation](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/adamic_adar/#procedure_implement). 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 in the candidate link. - `right_id`: `INT64`. ID of the second node in the candidate link. Additionally, the following variables are defined within the procedure: | Variable name | Variable type | Description | `aa_score` | Global [SumAgg aggregator value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | Accumulated Adamic-Adar score for the queried node pair. | `degree` | Node-attached [SumAgg aggregator value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | Per-node total degree used in log-inverse weighting. | `seen_left` | Node-attached [SumAgg aggregator value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | Per-node flag: node is a neighbor of the left query node. | `seen_right` | Node-attached [SumAgg aggregator value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | Per-node flag: node is a neighbor of the right query node. The following steps outline the logic of the procedure: 1. Compute each node's `degree` (undirected). 2. For the left node, mark all its neighbors with `seen_left`; for the right node, mark with `seen_right`. 3. For each common neighbor (both `seen_left` and `seen_right`), add `1 / log(degree)` to `aa_score`. 4. Return the Adamic-Adar score. ## Steps Run the following code blocks in order in the NebulaGraph Studio CONSOLE. For first-time setup, follow [Prepare algorithm sample data](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/prepare-data/) to check where to run commands and how the directory is mounted. ### 1. Prepare graph data[]() 1. Create a graph type that matches your data model. ```` ''' CREATE GRAPH TYPE IF NOT EXISTS adamic_adar_graph_type AS { NODE Node (LABEL Node {id INT PRIMARY KEY, rating INT}), EDGE Link (Node)-[LABEL Link {weight INT, MULTIEDGE KEY()}]->(Node) } ''' ```` 2. Download these CSV files and save them with their original names in `examples/algorithms/adamic_adar/` under your deployment directory: - [adamic_adar_node.csv](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/files/adamic_adar/adamic_adar_node.csv): Node data. - [adamic_adar_edge.csv](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/files/adamic_adar/adamic_adar_edge.csv): Edge data. Preview the CSV files adamic_adar_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 ```` adamic_adar_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 a temporary graph based on the graph type and load the data files into the temporary graph. ```` CREATE TEMPORARY GRAPH IF NOT EXISTS #adamic_adar_graph TYPED adamic_adar_graph_type ```` ```` ''' USE #adamic_adar_graph IMPORT INTO GRAPH { NODE (v@Node {id: id, rating: rating}) FROM DATAFILE { PATH: "file:///examples/algorithms/adamic_adar/adamic_adar_node.csv", FORMAT: "CSV", DELIMITER: ',' }, EDGE (id: src_id)-[e@Link {weight: weight}]->(id: dst_id) FROM DATAFILE { PATH: "file:///examples/algorithms/adamic_adar/adamic_adar_edge.csv", FORMAT: "CSV", DELIMITER: ',' } } ''' ```` After the import succeeds, run this query in the console to check the node count: ```` ''' USE #adamic_adar_graph MATCH (n) RETURN count(n) AS node_count ''' ```` The expected `node_count` is `24`. If it differs, [check the files and import results](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/prepare-data/#troubleshooting) before continuing. ### 2. Create a procedure[]() Create a procedure to implement the Adamic-Adar algorithm. For more information about the procedure, see [Procedure implementation](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/adamic_adar/#procedure_implement). ```` ''' CREATE OR REPLACE PROCEDURE adamic_adar_score(left_id INT64, right_id INT64) RETURNS (query_left_id INT64, query_right_id INT64, score DOUBLE) COMMENT "Compute the Adamic-Adar score between two nodes identified by vertex property id." AS { VALUE aa_score SumAgg = 0.0 NODE VALUE degree SumAgg = 0 NODE VALUE seen_left OrAgg = false NODE VALUE seen_right OrAgg = false MATCH (s)-[e]-(t) PER PATH { SET s.@degree += 1 } MATCH (s)-[e]-(n) WHERE s.id = left_id PER PATH { SET n.@seen_left += true } MATCH (s)-[e]-(n) WHERE s.id = right_id PER PATH { SET n.@seen_right += true } MATCH (n) WHERE n.@seen_left = true AND n.@seen_right = true AND n.id <> left_id AND n.id <> right_id AND n.@degree > 1 PER NODE (n) { SET @aa_score += 1.0 / ln(CAST(n.@degree AS DOUBLE)) } RETURN left_id AS query_left_id, right_id AS query_right_id, @aa_score AS score } ''' ```` ### 3. Call your procedure[]() Compute the Adamic-Adar score for nodes `6` and `9`. ```` USE #adamic_adar_graph CALL adamic_adar_score(6, 9) RETURN query_left_id, query_right_id, score ```` Returns: ```` +---------------+----------------+--------------------+ | query_left_id | query_right_id | score | +---------------+----------------+--------------------+ | 6 | 9 | 1.6743318796537416 | +---------------+----------------+--------------------+ ```` Save results to a file or graph To save the returned results as CSV files or write them to a graph, see [EXPORT](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/in-out/export/). Match the exported fields to the returned columns and target properties.