Skip to main content

Jaccard

UDTF: cugraph_jaccard

Official cuGraph reference: C API

Compare explicit vertex pairs by dividing the size of their shared-neighbor intersection by the size of their neighbor union.

Quickstart​

The call below supplies edges from registered relation target_edges with canonical src and dst columns and may include weight, plus the registered relation candidate_pairs (the vertex_pairs relation with columns first, second).

SELECT *
FROM cugraph_jaccard(
edges => (SELECT src, dst FROM target_edges),
vertex_pairs => (SELECT first, second FROM candidate_pairs)
);

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​

ArgumentRequiredColumnsDescription
edgesyes
  • src, dst: Int32, Int64, Utf8, LargeUtf8, Utf8View
  • weight (optional): Float32, Float64
  • edge_id (optional): Int32, Int64
edge relation with canonical src and dst columns, plus optional weight and edge_id columns
vertex_pairsyes
  • first, second: Int32, Int64, Utf8, LargeUtf8, Utf8View
explicit vertex pairs used by similarity scoring

Vertex columns of vertex_pairs must use the same vertex domain as edges: the integer type of src and dst, or any listed string type when the endpoints are strings. Every edge_id column must have the integer type of src and dst; string-keyed graphs accept no edge IDs.

Graph construction options​

This UDTF requires directed=false (undirected/symmetric graph). All other graph construction options follow the shared defaults documented in Graph Construction Options.

Output​

ColumnTypeNullableDescription
firstInt64|Utf8noFirst vertex from the explicit candidate-pair relation.
secondInt64|Utf8noSecond vertex from the explicit candidate-pair relation.
similarityFloat64noSimilarity coefficient for the explicit candidate pair.

These are generic descriptor schemas. Run gpu_validate_call to get the concrete, table-specific output schema.

Examples​

Which catalog entries are one brand listed twice?​

Sellers can enter the same brand under several names. Two entries liked by the same people are candidates for one brand. The input is every item_like event of the six months, reduced to distinct user-brand pairs.

Jaccard divides the shared fans of two entries by the union of their fan sets. The query scores all 1,999,000 pairs of the 2,000 most-liked brands in one call, then joins names and fan counts and keeps the 30 highest scores.

WITH fans AS (
SELECT -(e.user_id + 1) AS src, CAST(i.brand_id AS BIGINT) AS dst
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
GROUP BY e.user_id, i.brand_id
), top_brands AS (
SELECT dst AS brand_id, COUNT(*) AS fans FROM fans GROUP BY dst ORDER BY fans DESC, dst LIMIT 2000
), 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 ba.brand_name AS brand_a, bb.brand_name AS brand_b,
a.fans AS fans_a, b.fans AS fans_b, r.similarity AS jaccard
FROM cugraph_jaccard(
edges => (SELECT src, dst FROM fans),
vertex_pairs => (SELECT a.brand_id AS first, b.brand_id AS second
FROM top_brands a JOIN top_brands b ON a.brand_id < b.brand_id),
directed => false
) r
JOIN top_brands a ON a.brand_id = r.first
JOIN top_brands b ON b.brand_id = r.second
JOIN brands ba ON ba.brand_id = r.first
JOIN brands bb ON bb.brand_id = r.second
ORDER BY r.similarity DESC, brand_a
LIMIT 30;
Entry AEntry BFans AFans BJaccard
Tomorrow X TogetherTXT13,8808,2670.436
RilakkumaSan-X10,23214,3920.367
Baby TulaTula3,3983,8060.355
Air JordanJordan123,14972,4960.353
MuglerThierry Mugler6,2325,9250.348
FreebirdFreebird By Steven2,9494,1730.344
Hello KittySanrio72,010109,3590.337
Bandai Tamashii NationsSH Figuarts19,7429,9070.334
KonamiYu-Gi-Oh!12,9158,3400.324
Yves Saint LaurentYSL Yves Saint Laurent22,46023,8950.324
Christian DiorDior38,88337,6260.321
A Bathing ApeBape12,62013,2450.320
BabyBjornBABYBJÖRN2,9693,4340.320
HermèsHERMES8,9237,0510.320

The table shows the first 14 of 30 rows. The query took 3.34 s over Flight SQL.

Most of the highest-scoring pairs are one brand entered twice: TXT and Tomorrow X Together, Air Jordan and Jordan, Mugler and Thierry Mugler, Yves Saint Laurent and its YSL variant, Christian Dior and Dior, A Bathing Ape and Bape, Hermès and HERMES, BabyBjorn and BABYBJÖRN. No name was compared to find them. The remaining pairs are distinct brands that one audience follows together, such as Hello Kitty and Sanrio, Konami and Yu-Gi-Oh!, or Panini and Topps.

The pair list is a SQL relation, so the same query could join each pair's leaf categories or price ranges to separate duplicates from companions. Scores over the full six months hide seasonal pairs; a date filter on the events restricts the window.

The plan had 6 native fragments and zero host DataFusion boundaries. The largest query allocator peak was 75.07 GiB of the 90 GiB query limit. The capture contains the executed SQL, query IDs, timings and every result row.

Limits​

  • similarity is explicit-pair only; all-pairs candidate generation and all-pairs top-k search are not exposed
  • vertex_pairs is a required relation with canonical first and second columns
  • candidate-pair columns must match the graph vertex domain; logical string graphs accept Utf8, LargeUtf8, or Utf8View independently per column
  • null candidate-pair values are rejected at execution and are never dropped
  • candidate pairs are a multiset: duplicate, reversed, and self pairs remain distinct output rows
  • result rows have no global ordering; use ORDER BY when order is required
  • providing edges.weight selects weighted similarity; omitting it selects unit-weight similarity
  • cuGraph requires directed=false so the graph is constructed as an undirected/symmetric view