Source: https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/pagerank/ Documentation version: v5.3.2 # PageRank ## Algorithm introduction The PageRank algorithm is developed by Google to rank web pages in their search engine results. It works by counting the number of links to a page to determine a rough estimate of the importance of the page. The assumption is that more important pages are likely to receive more links from other pages. Each page is assigned a PageRank score that represents the importance of the page. The PageRank score of a page is calculated iteratively based on the scores of the pages that link to it. The formula for calculating the PageRank score of a page is as follows: \[ PR(i) = \frac{1 - d}{N} + d \sum_{j \in In(i)} \frac{PR(j)}{Out(j)} \] Where: - `PR(i)`: The PageRank score of page `i`. - `d`: The damping factor that represents the probability that a user follows a link from the current page to another page. Value range: [0, 1). - `N`: The total number of pages. - `In(i)`: The set of pages that link to page `i`. - `Out(j)`: The number of outbound links on page `j`. For more information about the PageRank algorithm, see [PageRank](https://en.wikipedia.org/wiki/PageRank). ## Data model To implement the PageRank algorithm in GQL, the following data model is used to create a graph type: - The web pages are abstracted as persons represented by nodes of type `Person`. - The links between pages are abstracted as relationships between persons, represented by edges of type `Knows`. For the complete definition of the graph type, see [Prepare graph data](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/pagerank/#1_prepare_graph_data). ## Procedure implementation To compute the PageRank scores of all nodes in a graph, a [procedure](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/procedures/create/) is created to implement the PageRank algorithm. For the complete definition of the procedure, see [Create a procedure](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/pagerank/#2_create_a_procedure). The following section describes the key components of the procedure and how it works. The procedure takes the following input parameters: - `damping`: The damping factor. - `max_iter`: The maximum number of iterations to perform. Additionally, the following variables are defined within the procedure: | Variable name | Variable type | Description | `cur_iter` | [Primitive value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/value-variable/) | The current iteration count. | `add_constant` | [Primitive value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/value-variable/) | The constant value added to each node's score in each iteration. This ensures that even nodes without incoming edges receive a score. | `delta` | Global [SumAgg aggregator value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | The total change in PageRank scores across all nodes in each iteration. This helps determine when to stop the iteration process. | `total_nodes` | Global [SumAgg aggregator value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | The total number of nodes in the graph. | `current_score` | Node-attached [SumAgg aggregator value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | The PageRank score of a node in the current iteration. | `next_score` | Node-attached [SumAgg aggregator value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | The PageRank score of a node in the next iteration. | `out_edge` | Node-attached [SumAgg aggregator value variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/agg/sum_agg/) | The number of outgoing edges from a node. | `result_file` | [File variable](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/variable-definition/file-variable/) | The file that stores the final PageRank scores of all nodes. The following steps outline the logic of the procedure: 1. Initialize `out_edge` for each node by counting its outgoing edges. 2. Initialize `total_nodes` by counting the total number of nodes in the graph. 3. Set `add_constant` to a constant value calculated based on the damping factor and total number of nodes. 4. Initialize `current_score` for each node to `1.0 / total_nodes`. 5. Start the iteration process to update PageRank scores until the maximum number of iterations (specified by `max_iter`) is reached or the convergence threshold is met (`delta` is less than or equal to `0.01`): 1. Reset `delta` to `0.0`. 2. For each edge, set `next_score` of the destination node to `current_score` of the source node divided by its `out_edge`, multiplied by the damping factor. 3. For each node, add `add_constant` to its `next_score`. 4. Calculate `delta` as the sum of absolute differences between `next_score` and `current_score` for all nodes. 5. Prepare for the next iteration by setting `current_score` to `next_score` and resetting `next_score` to `0.0`. 6. Increment the iteration count `cur_iter`. 6. After the final iteration ends, export the ID and final `current_score` of each node to `result_file`. ## 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 pagerank_graph_type AS { NODE Person (LABEL Person {id INT PRIMARY KEY, name STRING}), EDGE Knows (Person)-[LABEL Knows {MULTIEDGE KEY()}]->(Person) } ''' ```` 2. Download these CSV files and save them with their original names in `examples/algorithms/pagerank/` under your deployment directory: - [pagerank_node.csv](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/files/pagerank/pagerank_node.csv): Node data. - [pagerank_edge.csv](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/files/pagerank/pagerank_edge.csv): Edge data. Preview the CSV files pagerank_node.csv ```` u_id,u_name 1,Alice 2,Bob 3,Charlie 4,David ```` pagerank_edge.csv ```` src_id,dst_id 1,2 2,3 1,4 3,4 4,2 ```` 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 #pagerank_graph TYPED pagerank_graph_type ```` ```` ''' USE #pagerank_graph IMPORT INTO GRAPH { NODE (v@Person {id: u_id, name: u_name}) FROM DATAFILE { PATH: "file:///examples/algorithms/pagerank/pagerank_node.csv", FORMAT: "CSV", DELIMITER: ',' }, EDGE (id: src_id)-[e@Knows{}]->(id: dst_id) FROM DATAFILE { PATH: "file:///examples/algorithms/pagerank/pagerank_edge.csv", FORMAT: "CSV", DELIMITER: ',' } } ''' ```` After the import succeeds, run this query in the console to check the node count: ```` ''' USE #pagerank_graph MATCH (n) RETURN count(n) AS node_count ''' ```` The expected `node_count` is `4`. 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 PageRank algorithm. For more information about the procedure, see [Procedure implementation](https://dev-docs.nebula-graph.io/v5.3.2/analytic/algorithms/pagerank/#procedure_implementation). ```` ''' CREATE OR REPLACE PROCEDURE pagerank(damping DOUBLE, max_iter INT) RETURNS () AS { VALUE cur_iter INT64 = 1 VALUE add_constant DOUBLE = 1.0 - damping VALUE delta SumAgg = 1.0 VALUE total_nodes SumAgg = 0 NODE VALUE current_score SumAgg = 0.0 NODE VALUE next_score SumAgg = 0.0 NODE VALUE out_edge SumAgg = 0 FILE result_file {vid INT64, score DOUBLE} = DATAFILE {PATH:"file:///examples/algorithms/pagerank/output", FORMAT:"CSV", INCLUDE_HEADER: true} MATCH (s:Person)-[e:Knows]->(t:Person) PER PATH { SET s.@out_edge += 1 } MATCH (s:Person) PER NODE (s) { SET @total_nodes += 1 } SET add_constant = add_constant / @total_nodes MATCH (s:Person) PER NODE (s) { SET s.@current_score = 1.0 / @total_nodes } LOG_INFO("Start Iteration") WHILE cur_iter <= max_iter AND @delta > 0.01 THEN { LOG_INFO("current iter: ", cur_iter) SET @delta = 0.0 MATCH (s:Person)-[e:Knows]->(t:Person) PER PATH { SET t.@next_score += damping * s.@current_score / s.@out_edge } MATCH (s:Person) PER NODE (s) { SET s.@next_score += add_constant } MATCH (s:Person) PER NODE (s) { SET @delta += abs(s.@next_score - s.@current_score) } MATCH (s:Person) PER NODE (s) { SET s.@current_score = s.@next_score SET s.@next_score = 0.0 } SET cur_iter = cur_iter + 1 } LOG_INFO("Finish Iteration") LOG_INFO("Final @delta: " , @delta) MATCH (s:Person) PER NODE (s) { EXPORT s.id, s.@current_score INTO result_file } } ''' ```` ### 3. Call your procedure Call the procedure to compute the PageRank scores. The following example sets the damping factor to `0.85` and the maximum number of iterations to `30`. ```` USE #pagerank_graph CALL pagerank(0.85, 30) FINISH ```` This call writes the results to CSV files and does not return a table in the console. Return: Example execution log ```` Log: 2025-09-24T21:19:18.213020 INFO - Start Iteration 2025-09-24T21:19:18.213542 INFO - current iter: 1 2025-09-24T21:19:18.225369 INFO - current iter: 2 2025-09-24T21:19:18.236810 INFO - current iter: 3 2025-09-24T21:19:18.246852 INFO - current iter: 4 2025-09-24T21:19:18.257173 INFO - current iter: 5 2025-09-24T21:19:18.267120 INFO - current iter: 6 2025-09-24T21:19:18.276807 INFO - current iter: 7 2025-09-24T21:19:18.286623 INFO - current iter: 8 2025-09-24T21:19:18.296545 INFO - current iter: 9 2025-09-24T21:19:18.306014 INFO - current iter: 10 2025-09-24T21:19:18.315761 INFO - current iter: 11 2025-09-24T21:19:18.325485 INFO - current iter: 12 2025-09-24T21:19:18.335015 INFO - current iter: 13 2025-09-24T21:19:18.344843 INFO - current iter: 14 2025-09-24T21:19:18.354806 INFO - current iter: 15 2025-09-24T21:19:18.365031 INFO - current iter: 16 2025-09-24T21:19:18.375710 INFO - current iter: 17 2025-09-24T21:19:18.385460 INFO - current iter: 18 2025-09-24T21:19:18.395477 INFO - current iter: 19 2025-09-24T21:19:18.405343 INFO - current iter: 20 2025-09-24T21:19:18.414832 INFO - Finish Iteration 2025-09-24T21:19:18.414987 INFO - Final @delta: 0.00968988 ```` On the Docker host, open the CSV files in `examples/algorithms/pagerank/output/` under your deployment directory. Example contents: ```` "vid","score" 1,0.037500000000000006 2,0.32800999035091527 3,0.316308491798278 4,0.3181815178508066 ```` Write results to a graph If you need to persist PageRank results in a graph, use the approach in [EXPORT](https://dev-docs.nebula-graph.io/v5.3.2/database-gql-reference/in-out/export/): - Export PageRank output fields to a table variable first (typically `id` and `score`). - For a remote graph, split table rows with `table_split(...)` and send batched `USE + INSERT` statements via `nebula_exec`. Define the target graph type to include a rank score property (for example, `pagerank_score` on `Person`).