PageRank
UDTF: cugraph_pagerank
Official cuGraph reference: C API
Rank vertices by the stationary probability of a damped random walk that follows outgoing edges.
Quickstart
The call below supplies edges from registered relation target_edges with canonical src and dst columns and may include weight.
SELECT *
FROM cugraph_pagerank(
edges => (SELECT src, dst FROM target_edges)
);
Inputs
Every relation is a named parenthesized SELECT subquery. The required edges role uses canonical src and dst columns. Every role, its canonical columns, and their accepted Arrow types are listed under Relation arguments. Metadata validation resolves registered tables named in its JSON request.
The vertex-ID types this UDTF accepts, the numeric types a per-call codebook maps to native ids, and its string-key limits are listed in Vertex ID support; the concrete call-specific schema comes from gpu_validate_call.
Arguments and options
Relation arguments
Every edge_id column must have the integer type of src and dst; string-keyed graphs accept no edge IDs.
Named value arguments
Graph construction options
Graph construction follows the shared defaults (directed=true, renumbering, python_cugraph policy) documented in Graph Construction Options.
Output
These are generic descriptor schemas. Run gpu_validate_call to get the concrete, table-specific output schema.
Examples
- MerRec
- Citation network
Which brands grew closer to Barbie's audience?
The query compares each brand's affinity to Barbie's audience from May through June against July through August 2023 and ranks the relative change. A later check of product names tests whether the change coincides with Barbie-related listings.
Each period has a graph of distinct user-brand likes. The after_release
flag is true for July to August likes. The split at 1 July falls 20 days
before the Barbie film opened on 21 July. User vertices are -(user_id + 1)
and brand vertices are brand_id values. Both columns are non-negative in
this data, so users occupy negative IDs and la.vertex > 0 keeps only brands
(brand 0 is excluded).
Personalized PageRank starts from Barbie; ordinary PageRank supplies each
brand's global graph score. Their ratio, lift, describes relative graph
affinity: 1 means the two scores are equal. All four calls use the default
options (alpha 0.85, epsilon 1e-5, max_iterations 100), and each
converged before the iteration limit. Lifts from the two periods were
therefore computed to one tolerance. The query ranks the change in that ratio
and requires at least 1,000 fans (distinct users) per brand in both periods.
WITH likes AS (
SELECT DISTINCT -(e.user_id + 1) AS src, CAST(i.brand_id AS BIGINT) AS dst,
e.event_time >= TIMESTAMP '2023-07-01 00:00:00' AS after_release
FROM merrec_events e JOIN merrec_items i ON i.item_id = e.item_id
WHERE e.event_type = 'item_like' AND i.brand_id <> 0
AND e.event_time >= TIMESTAMP '2023-05-01 00:00:00'
AND e.event_time < TIMESTAMP '2023-09-01 00:00:00'
), lift_before AS (
SELECT p.vertex, p.value / r.value AS lift
FROM cugraph_personalized_pagerank(
edges => (SELECT src, dst FROM likes WHERE NOT after_release),
personalization => (SELECT 2595 AS vertex, 1.0 AS value),
directed => false) p
JOIN cugraph_pagerank(
edges => (SELECT src, dst FROM likes WHERE NOT after_release), directed => false) r
ON r.vertex = p.vertex
), lift_after AS (
SELECT p.vertex, p.value / r.value AS lift
FROM cugraph_personalized_pagerank(
edges => (SELECT src, dst FROM likes WHERE after_release),
personalization => (SELECT 2595 AS vertex, 1.0 AS value),
directed => false) p
JOIN cugraph_pagerank(
edges => (SELECT src, dst FROM likes WHERE after_release), directed => false) r
ON r.vertex = p.vertex
), fans AS (
SELECT dst AS brand_id,
SUM(CASE WHEN after_release THEN 0 ELSE 1 END) AS fans_before,
SUM(CASE WHEN after_release THEN 1 ELSE 0 END) AS fans_after
FROM likes GROUP BY dst
), brands AS (
SELECT CAST(brand_id AS BIGINT) AS brand_id, MIN(brand_name) AS brand_name
FROM merrec_items WHERE brand_id <> 0 GROUP BY brand_id
)
SELECT b.brand_name, f.fans_before, f.fans_after,
lb.lift AS lift_before, la.lift AS lift_after, la.lift / lb.lift AS lift_change
FROM lift_after la
JOIN lift_before lb ON lb.vertex = la.vertex
JOIN fans f ON f.brand_id = la.vertex
JOIN brands b ON b.brand_id = la.vertex
WHERE la.vertex > 0 AND la.vertex <> 2595
AND f.fans_before >= 1000 AND f.fans_after >= 1000
ORDER BY lift_change DESC, b.brand_name
LIMIT 25;
The first four rows are the largest increases. Taylor Swift is included as a comparison for the product-name check below.
The time filters, four graph calls and brand joins ran natively in one plan. Over Flight SQL, the first run on a fresh server took 3.72 s and runs 2 to 4 a median of 3.05 s. On the same host, with the files in the page cache, an equivalent CPU pipeline combining 32-thread DuckDB with igraph took a median of 23.3 s (2.3 s SQL extraction, 13.0 s renumbering and graph construction, 7.7 s for four PageRank calls, 0.3 s final join) with identical top-25 rankings. Device execution avoids transferring and renumbering the 23 million edge pairs across host memory.
Follow-up: check product names. The graph query did not search names.
This separate SQL counts like events on listings whose names contain
"Barbie", using the same periods. Each of the five brand names checked here
maps to one brand_id, matching the brands in the graph result.
WITH selected_items AS (
SELECT item_id, brand_name,
LOWER(COALESCE(name, '')) LIKE '%barbie%' AS is_barbie
FROM merrec_items
WHERE brand_name IN ('NYX', 'Amc', 'Primark', 'ALDO', 'Taylor Swift', 'Stanley', 'OPI', 'ZARA')
), likes AS (
SELECT i.brand_name, i.is_barbie,
e.event_time < TIMESTAMP '2023-07-01 00:00:00' AS may_june
FROM merrec_events e JOIN selected_items i ON i.item_id = e.item_id
WHERE e.event_type = 'item_like'
AND e.event_time >= TIMESTAMP '2023-05-01 00:00:00'
AND e.event_time < TIMESTAMP '2023-09-01 00:00:00'
)
SELECT brand_name,
SUM(CASE WHEN may_june THEN 1 ELSE 0 END) AS total_likes_may_june,
SUM(CASE WHEN NOT may_june THEN 1 ELSE 0 END) AS total_likes_july_august,
SUM(CASE WHEN may_june AND is_barbie THEN 1 ELSE 0 END) AS barbie_likes_may_june,
SUM(CASE WHEN NOT may_june AND is_barbie THEN 1 ELSE 0 END) AS barbie_likes_july_august
FROM likes
GROUP BY brand_name
ORDER BY brand_name;
NYX's records include "LIMITED EDITION NYX Barbie Flip Phone Mirror". Taylor Swift's graph score also increased, but only 135 of 164,499 later likes were on matching listings. Its change remains unexplained by this check. Name matches can include seller descriptions and color names.
Follow-up: change the seed. A rise in graph affinity could reflect a
broad summer trend rather than Barbie. Rerunning the query with
another seed brand tests that. Hot Wheels is a Mattel brand whose collector
audience overlaps Barbie's; Nike is a large brand with no July event. Each
control replaces Barbie's brand_id (2595) with the seed's (9877 for Hot
Wheels, 15987 for Nike) in the personalization vertex and the la.vertex <>
exclusion. The rest of the SQL is unchanged.
With Nike as the seed, none of the four brands appears among the 25 largest changes. With Hot Wheels, NYX, ALDO and Primark appear with smaller changes and Amc is absent, consistent with the Mattel collector audience sharing part of the Barbie movement. Item attributes are the latest retained values.
The graph capture contains all 25 brands, query IDs and timings. The listing capture and control captures contain the follow-up SQL and full results.
These examples run on the citation network demo dataset
(4.9M papers, 45.6M src-cites-dst edges).
Which papers rank highest when citations from influential papers count more?
Raw citation counts treat each incoming citation equally. PageRank weights citations by the scores of the citing papers, and the metadata join lets us compare that ranking with each paper's reported citation count.
SELECT p.title, p.year, p.n_citation, r.value AS pagerank
FROM cugraph_pagerank(edges => (SELECT src, dst FROM citation_edges)) r
JOIN papers p ON p.paper_id = r.vertex
ORDER BY r.value DESC
LIMIT 5;
Where does the original PageRank paper rank by its own algorithm?
Ranking the paper that introduced PageRank by its own method gives a concrete reference point in this corpus. The corpus has two 1998 records with this title, so the query selects the Web Conference record by year and venue.
WITH ranked AS (
SELECT vertex, value, ROW_NUMBER() OVER (ORDER BY value DESC) AS rank
FROM cugraph_pagerank(edges => (SELECT src, dst FROM citation_edges)))
SELECT r.rank, p.title, p.year, r.value
FROM ranked r JOIN papers p ON p.paper_id = r.vertex
WHERE p.title = 'The anatomy of a large-scale hypertextual Web search engine'
AND p.year = 1998 AND p.venue = 'The Web Conference';
Which papers were central to the citation network through 2000?
An era-specific ranking can surface papers that structure literature from that period. This query keeps citations whose source and destination papers are both dated 1901 through 2000 (3,431,911 edges across 518,777 active vertices), then ranks that subgraph with PageRank.
CREATE OR REPLACE VIEW edges_pre2000 AS
SELECT e.src, e.dst
FROM citation_edges e
JOIN papers ps ON ps.paper_id = e.src
JOIN papers pd ON pd.paper_id = e.dst
WHERE ps.year BETWEEN 1901 AND 2000 AND pd.year BETWEEN 1901 AND 2000;
SELECT p.year, p.title
FROM cugraph_pagerank(edges => (SELECT src, dst FROM edges_pre2000)) r
JOIN papers p ON p.paper_id = r.vertex
ORDER BY r.value DESC
LIMIT 6;
Limits
- calls without an edge weight column repeat between runs; with one, scores can differ in the last digits because out-weight sums accumulate with floating-point atomics