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:
Where:
PR(i): The PageRank score of pagei.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 pagei.Out(j): The number of outbound links on pagej.
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:
- Initialize
out_edgefor each node by counting its outgoing edges. - Initialize
total_nodesby counting the total number of nodes in the graph. - Set
add_constantto a constant value calculated based on the damping factor and total number of nodes. - Initialize
current_scorefor each node to1.0 / total_nodes. - 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 (deltais less than or equal to0.01):- Reset
deltato0.0. - For each edge, set
next_scoreof the destination node tocurrent_scoreof the source node divided by itsout_edge, multiplied by the damping factor. - For each node, add
add_constantto itsnext_score. - Calculate
deltaas the sum of absolute differences betweennext_scoreandcurrent_scorefor all nodes. - Prepare for the next iteration by setting
current_scoretonext_scoreand resettingnext_scoreto0.0. - Increment the iteration count
cur_iter.
- Reset
- After the final iteration ends, export the ID and final
current_scoreof each node toresult_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¶
-
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) } ''' -
Download these CSV files and save them with their original names in
examples/algorithms/pagerank/under your deployment directory:- pagerank_node.csv: Node data.
- pagerank_edge.csv: Edge data.
Preview the CSV files
pagerank_node.csvu_id,u_name 1,Alice 2,Bob 3,Charlie 4,Davidpagerank_edge.csvsrc_id,dst_id 1,2 2,3 1,4 3,4 4,2 -
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_countis4. 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
idandscore). - For a remote graph, split table rows with
table_split(...)and send batchedUSE + INSERTstatements vianebula_exec.
Define the target graph type to include a rank score property (for example, pagerank_score on Person).