Skip to content
Developer Edition runs on one host and does not require a product license file. Need multi-host deployment or performance testing at scale? Explore Enterprise Edition

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.

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.

Procedure implementation

To compute the PageRank scores of all nodes in a graph, a procedure is created to implement the PageRank algorithm.

For the complete definition of the procedure, see 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 The current iteration count.
add_constant Primitive 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 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 The total number of nodes in the graph.
current_score Node-attached SumAgg aggregator value variable The PageRank score of a node in the current iteration.
next_score Node-attached SumAgg aggregator value variable The PageRank score of a node in the next iteration.
out_edge Node-attached SumAgg aggregator value variable The number of outgoing edges from a node.
result_file 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 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:

    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 before continuing.

2. Create a procedure

Create a procedure to implement the PageRank algorithm. For more information about the procedure, see 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<DOUBLE> = 1.0
    VALUE total_nodes SumAgg<INT> = 0
    NODE VALUE current_score SumAgg<DOUBLE> = 0.0
    NODE VALUE next_score SumAgg<DOUBLE> = 0.0
    NODE VALUE out_edge SumAgg<INT64> = 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:

  • 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).