Graph-Based Movie Recommender

Hybrid recommendations on a sparse user–movie graph: Jaccard taste similarity, FastRP-style embeddings + kNN, Louvain communities, and content boosts from genre/director overlap.

Source: assignments/recommender (20 users · 25 movies · 101 ratings) · offline GDS-equivalent precompute

20

Users

25

Movies

101

Ratings

4

Taste communities

Nodes by label

User20
Movie25
Genre14
Director21

Relationships by type

RATED101
IN_GENRE50
DIRECTED_BY25

Graph model

Users rate movies; movies link to genres and directors used for the hybrid content boost.

RATEDIN_GENREDIRECTED_BYUserMovieGenreDirector

Exploratory analysis

Frozen Cypher-style EDA from the notebook: activity, rating shape, genres, directors, and overlap.

Graph size

Node and relationship counts after enrichment.

7 rows
MATCH (n) RETURN labels(n)[0] AS label, count(*) AS count
ORDER BY count DESC
UNION ALL
MATCH ()-[r]->() RETURN type(r) AS label, count(*) AS count
labelcount
User20
Movie25
Genre14
Director21
RATED101
IN_GENRE50
DIRECTED_BY25

Top 5 most active users

Users with the most ratings.

5 rows
MATCH (u:User)-[r:RATED]->(:Movie)
RETURN u.userId AS userId, u.name AS name, count(r) AS ratingsGiven, round(avg(r.rating),2) AS avgRating
ORDER BY ratingsGiven DESC LIMIT 5
userIdnameratingsGivenavgRating
U001Alice Chen64.67
U013Maya Patel54.8
U017Quinn Zhang54.8
U003Carol White54.6
U005Eva Rossi54.6

Top 10 movies by number of ratings

Most-rated movies with average user rating vs catalog avgRating.

10 rows
MATCH (m:Movie)<-[r:RATED]-(:User)
RETURN m.movieId AS movieId, m.title AS title, count(r) AS numRatings, round(avg(r.rating),2) AS avgUserRating, m.avgRating AS avgRating
ORDER BY numRatings DESC LIMIT 10
movieIdtitlenumRatingsavgUserRatingavgRating
M002Inception74.578.8
M006Pulp Fiction74.148.9
M003The Godfather64.679.2
M001The Matrix64.678.7
M01412 Angry Men54.89
M019Dune54.68
M022Portrait of a Lady on Fire54.68.1
M007The Dark Knight459
M025Blade Runner 204944.758
M005Interstellar44.758.6

Rating distribution

How many ratings fall in each 1–5 bucket.

3 rows
MATCH ()-[r:RATED]->() RETURN r.rating AS rating, count(*) AS count ORDER BY rating
ratingcount
36
441
554

Genre statistics

Movies, ratings, and average rating per genre.

14 rows
MATCH (m:Movie)-[:IN_GENRE]->(g:Genre)
OPTIONAL MATCH (m)<-[r:RATED]-()
RETURN g.name AS genre, count(DISTINCT m) AS movieCount, count(r) AS totalRatings, round(avg(r.rating),2) AS avgRating
ORDER BY movieCount DESC
genremovieCounttotalRatingsavgRating
Drama14574.44
Sci-Fi8354.57
Action4184.67
Crime4224.59
Thriller4164.44
Biography394.11
Comedy3104.4
Romance3124.5
Mystery264.67
Adventure134
Showing 1–10 of 14 rows

Director statistics

Movies and average user rating per director.

21 rows
MATCH (m:Movie)-[:DIRECTED_BY]->(d:Director)
OPTIONAL MATCH (m)<-[r:RATED]-()
RETURN d.name AS director, count(DISTINCT m) AS movieCount, round(avg(r.rating),2) AS avgUserRating
ORDER BY movieCount DESC
directormovieCountavgUserRating
Christopher Nolan34.77
Damien Chazelle24.42
Denis Villeneuve24.67
Alejandro G. Iñárritu14
Alfonso Cuarón14
Barry Jenkins14.67
Bong Joon-ho14.67
Céline Sciamma14.6
Daniels14.33
David Fincher13.5
Showing 1–10 of 21 rows

Most polarizing movies

Highest rating standard deviation among movies with ≥3 ratings.

10 rows
MATCH (m:Movie)<-[r:RATED]-(:User)
WITH m, count(r) AS numRatings, avg(r.rating) AS avgUserRating, stDev(r.rating) AS stDev
WHERE numRatings >= 3
RETURN m.movieId AS movieId, m.title AS title, numRatings, round(avgUserRating,2) AS avgUserRating, round(stDev,2) AS stDev
ORDER BY stDev DESC LIMIT 10
movieIdtitlenumRatingsavgUserRatingstDev
M009Whiplash34.331.15
M024The Revenant341
M020Roma440.82
M006Pulp Fiction74.140.69
M018La La Land44.50.58
M008Spirited Away44.50.58
M015Everything Everywhere All at Once34.330.58
M010Get Out33.670.58
M012Her34.330.58
M021Knives Out34.670.58

High-overlap user pairs

Users who co-rated the most movies, with average absolute rating difference.

10 rows
MATCH (u1:User)-[:RATED]->(m:Movie)<-[:RATED]-(u2:User)
WHERE u1.userId < u2.userId
WITH u1, u2, count(m) AS coRated, avg(abs((u1)-[:RATED]->(m)).rating - ((u2)-[:RATED]->(m)).rating) AS avgAbsDiff
RETURN u1.userId AS user1, u2.userId AS user2, coRated, round(avgAbsDiff,2) AS avgAbsDiff
ORDER BY coRated DESC LIMIT 10
user1user1Nameuser2user2NamecoRatedavgAbsDiff
U007Grace LiuU020Tom Anderson50.4
U007Grace LiuU016Paul Garcia50.6
U008Henry ParkU018Ryan Murphy50.6
U011Karen SinghU017Quinn Zhang50.6
U016Paul GarciaU020Tom Anderson50.6
U002Bob MartinezU004David Kim50.8
U014Noah WilliamsU018Ryan Murphy51
U008Henry ParkU014Noah Williams51.2
U013Maya PatelU017Quinn Zhang40
U001Alice ChenU017Quinn Zhang40.25

Per-user genre preference

Each user's highest-average genre among genres they rated.

20 rows
MATCH (u:User)-[r:RATED]->(m:Movie)-[:IN_GENRE]->(g:Genre)
WITH u, g, avg(r.rating) AS avgRating, count(*) AS ratingsInGenre
ORDER BY avgRating DESC
WITH u, collect({genre:g.name, avgRating:avgRating, ratingsInGenre:ratingsInGenre})[0] AS top
RETURN u.userId AS userId, u.name AS name, top.genre AS topGenre, round(top.avgRating,2) AS avgRating, top.ratingsInGenre AS ratingsInGenre
userIdnametopGenreavgRatingratingsInGenre
U001Alice ChenThriller51
U002Bob MartinezCrime4.673
U003Carol WhiteAnimation51
U004David KimMusic51
U005Eva RossiComedy51
U006Frank OseiThriller4.673
U007Grace LiuThriller51
U008Henry ParkCrime4.673
U009Iris NovakRomance52
U010James BrownMystery52
Showing 1–10 of 20 rows

User similarity (GDS pipeline)

Users connected by the selected similarity metric only (Jaccard or kNN). Node positions follow those edges; switch the dropdown to compare layouts. Colors = Louvain community.

C0 C1 C2 C3

Scroll or pinch to zoom · drag background to pan · drag nodes to rearrange

AliceBobCarolDavidEvaFrankGraceHenryIrisJamesKarenLeoMayaNoahOliviaPaulQuinnRyanSaraTom

Jaccard vs kNN comparison

User 1 User 2 Jaccard kNN
U001U0070.5710.693
U001U0110.5710.615
U001U0130.5710.709
U001U0160.5710.635
U001U0170.5710.706
U001U0200.5710.689
U002U0030.251
U002U00410.969
U002U0050.246
U002U0060.1110.289
Showing 1–10 of 70 pairs

Recommendations

Precomputed for every user. Collaborative uses similar users' high ratings (≥4); hybrid adds genre/director overlap against the target's liked movies.

Pick a user to load precomputed recommendations and an ego-network view.

Taste communities

Louvain on the Jaccard user–user graph — 4 communities, modularity 0.612.

Community 0

7 members · avg age 34.29

Top genres

Crime (5) Drama (4.75) Action (4.67) Sci-Fi (4.59) Thriller (4.57)

Occupations

Software Engineer ×1Manager ×1Engineer ×1Scientist ×1Consultant ×1

Members

Alice ChenGrace LiuKaren SinghMaya PatelPaul GarciaQuinn ZhangTom Anderson

Community 1

5 members · avg age 46.6

Top genres

Crime (4.53) Drama (4.24) Adventure (4) Music (4) Biography (3.6)

Occupations

Teacher ×1Doctor ×1Accountant ×1Architect ×1Retired ×1

Members

Bob MartinezDavid KimHenry ParkNoah WilliamsRyan Murphy

Community 2

5 members · avg age 27.8

Top genres

Music (5) Biography (4.75) Romance (4.62) Drama (4.56) Animation (4.5)

Occupations

Student ×2Designer ×1Chef ×1Writer ×1

Members

Carol WhiteEva RossiIris NovakLeo TanakaOlivia Jones

Community 3

3 members · avg age 31

Top genres

Mystery (4.67) Comedy (4.67) Drama (4.5) Thriller (4.38) Crime (4.33)

Occupations

Journalist ×1Lawyer ×1Nurse ×1

Members

Frank OseiJames BrownSara Hassan