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
| User | 20 |
| Movie | 25 |
| Genre | 14 |
| Director | 21 |
Relationships by type
| RATED | 101 |
| IN_GENRE | 50 |
| DIRECTED_BY | 25 |
Graph model
Users rate movies; movies link to genres and directors used for the hybrid content boost.
Exploratory analysis
Frozen Cypher-style EDA from the notebook: activity, rating shape, genres, directors, and overlap.
Graph size
Node and relationship counts after enrichment.
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| label | count |
|---|---|
| User | 20 |
| Movie | 25 |
| Genre | 14 |
| Director | 21 |
| RATED | 101 |
| IN_GENRE | 50 |
| DIRECTED_BY | 25 |
Top 5 most active users
Users with the most ratings.
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| userId | name | ratingsGiven | avgRating |
|---|---|---|---|
| U001 | Alice Chen | 6 | 4.67 |
| U013 | Maya Patel | 5 | 4.8 |
| U017 | Quinn Zhang | 5 | 4.8 |
| U003 | Carol White | 5 | 4.6 |
| U005 | Eva Rossi | 5 | 4.6 |
Top 10 movies by number of ratings
Most-rated movies with average user rating vs catalog avgRating.
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| movieId | title | numRatings | avgUserRating | avgRating |
|---|---|---|---|---|
| M002 | Inception | 7 | 4.57 | 8.8 |
| M006 | Pulp Fiction | 7 | 4.14 | 8.9 |
| M003 | The Godfather | 6 | 4.67 | 9.2 |
| M001 | The Matrix | 6 | 4.67 | 8.7 |
| M014 | 12 Angry Men | 5 | 4.8 | 9 |
| M019 | Dune | 5 | 4.6 | 8 |
| M022 | Portrait of a Lady on Fire | 5 | 4.6 | 8.1 |
| M007 | The Dark Knight | 4 | 5 | 9 |
| M025 | Blade Runner 2049 | 4 | 4.75 | 8 |
| M005 | Interstellar | 4 | 4.75 | 8.6 |
Rating distribution
How many ratings fall in each 1–5 bucket.
MATCH ()-[r:RATED]->() RETURN r.rating AS rating, count(*) AS count ORDER BY rating| rating | count |
|---|---|
| 3 | 6 |
| 4 | 41 |
| 5 | 54 |
Genre statistics
Movies, ratings, and average rating per genre.
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| genre | movieCount | totalRatings | avgRating |
|---|---|---|---|
| Drama | 14 | 57 | 4.44 |
| Sci-Fi | 8 | 35 | 4.57 |
| Action | 4 | 18 | 4.67 |
| Crime | 4 | 22 | 4.59 |
| Thriller | 4 | 16 | 4.44 |
| Biography | 3 | 9 | 4.11 |
| Comedy | 3 | 10 | 4.4 |
| Romance | 3 | 12 | 4.5 |
| Mystery | 2 | 6 | 4.67 |
| Adventure | 1 | 3 | 4 |
Director statistics
Movies and average user rating per director.
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| director | movieCount | avgUserRating |
|---|---|---|
| Christopher Nolan | 3 | 4.77 |
| Damien Chazelle | 2 | 4.42 |
| Denis Villeneuve | 2 | 4.67 |
| Alejandro G. Iñárritu | 1 | 4 |
| Alfonso Cuarón | 1 | 4 |
| Barry Jenkins | 1 | 4.67 |
| Bong Joon-ho | 1 | 4.67 |
| Céline Sciamma | 1 | 4.6 |
| Daniels | 1 | 4.33 |
| David Fincher | 1 | 3.5 |
Most polarizing movies
Highest rating standard deviation among movies with ≥3 ratings.
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| movieId | title | numRatings | avgUserRating | stDev |
|---|---|---|---|---|
| M009 | Whiplash | 3 | 4.33 | 1.15 |
| M024 | The Revenant | 3 | 4 | 1 |
| M020 | Roma | 4 | 4 | 0.82 |
| M006 | Pulp Fiction | 7 | 4.14 | 0.69 |
| M018 | La La Land | 4 | 4.5 | 0.58 |
| M008 | Spirited Away | 4 | 4.5 | 0.58 |
| M015 | Everything Everywhere All at Once | 3 | 4.33 | 0.58 |
| M010 | Get Out | 3 | 3.67 | 0.58 |
| M012 | Her | 3 | 4.33 | 0.58 |
| M021 | Knives Out | 3 | 4.67 | 0.58 |
High-overlap user pairs
Users who co-rated the most movies, with average absolute rating difference.
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| user1 | user1Name | user2 | user2Name | coRated | avgAbsDiff |
|---|---|---|---|---|---|
| U007 | Grace Liu | U020 | Tom Anderson | 5 | 0.4 |
| U007 | Grace Liu | U016 | Paul Garcia | 5 | 0.6 |
| U008 | Henry Park | U018 | Ryan Murphy | 5 | 0.6 |
| U011 | Karen Singh | U017 | Quinn Zhang | 5 | 0.6 |
| U016 | Paul Garcia | U020 | Tom Anderson | 5 | 0.6 |
| U002 | Bob Martinez | U004 | David Kim | 5 | 0.8 |
| U014 | Noah Williams | U018 | Ryan Murphy | 5 | 1 |
| U008 | Henry Park | U014 | Noah Williams | 5 | 1.2 |
| U013 | Maya Patel | U017 | Quinn Zhang | 4 | 0 |
| U001 | Alice Chen | U017 | Quinn Zhang | 4 | 0.25 |
Per-user genre preference
Each user's highest-average genre among genres they rated.
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| userId | name | topGenre | avgRating | ratingsInGenre |
|---|---|---|---|---|
| U001 | Alice Chen | Thriller | 5 | 1 |
| U002 | Bob Martinez | Crime | 4.67 | 3 |
| U003 | Carol White | Animation | 5 | 1 |
| U004 | David Kim | Music | 5 | 1 |
| U005 | Eva Rossi | Comedy | 5 | 1 |
| U006 | Frank Osei | Thriller | 4.67 | 3 |
| U007 | Grace Liu | Thriller | 5 | 1 |
| U008 | Henry Park | Crime | 4.67 | 3 |
| U009 | Iris Novak | Romance | 5 | 2 |
| U010 | James Brown | Mystery | 5 | 2 |
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.
Scroll or pinch to zoom · drag background to pan · drag nodes to rearrange
Jaccard vs kNN comparison
| User 1 | User 2 | Jaccard | kNN |
|---|---|---|---|
| U001 | U007 | 0.571 | 0.693 |
| U001 | U011 | 0.571 | 0.615 |
| U001 | U013 | 0.571 | 0.709 |
| U001 | U016 | 0.571 | 0.635 |
| U001 | U017 | 0.571 | 0.706 |
| U001 | U020 | 0.571 | 0.689 |
| U002 | U003 | — | 0.251 |
| U002 | U004 | 1 | 0.969 |
| U002 | U005 | — | 0.246 |
| U002 | U006 | 0.111 | 0.289 |
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
Top genres
Occupations
Members
Community 1
Top genres
Occupations
Members
Community 2
Top genres
Occupations
Members
Community 3
Top genres
Occupations
Members