Challenge: Create a user-genre projection
You’ve learned how to create projections with multiple node types. Now it’s your turn to create one independently.
Your task: Create a bipartite projection of Users and Genres that preserves their labels and connects them through the movies they rated.
This projection would be useful for:
-
Understanding user genre preferences
-
Finding users with similar genre tastes
-
Genre-based recommendation systems
Requirements
Your projection should:
-
Include User and Genre nodes with labels preserved
-
Connect users to genres through the movies they rated
-
Preserve relationship types
-
Name the projection
'users-genres'
Hints
You’ll need a two-hop pattern:
-
User rates a Movie
-
That Movie is in a Genre
-
Therefore, User connects to Genre
Remember the configuration parameters:
-
sourceNodeLabelsfor source node labels -
targetNodeLabelsfor target node labels -
relationshipTypefor relationship types
Solution approach
Details
MATCH (source:User)-[:RATED]->(:Movie)-[r:IN_GENRE]->(target:Genre) // (1)
WITH gds.graph.project( // (2)
'users-genre', // (3)
source, // (4)
target, // (5)
{
sourceNodeLabels: labels(source), // (6)
targetNodeLabels: labels(target), // (7)
relationshipType: type(r) // (8)
},
{}
) AS g
RETURN g.graphName AS graph, g.nodeCount AS nodes, g.relationshipCount AS rels // (9)Projection breakdown
-
Match User nodes connected to Genre nodes through Movie nodes
-
Call the GDS projection function
-
Name the projection 'users-genres'
-
Include source (User) nodes
-
Include target (Genre) nodes
-
Preserve source node labels
-
Preserve target node labels
-
Preserve relationship types
-
Return projection statistics
Key components:
-
MATCH pattern connects users to genres through movies
-
Configuration preserves User and Genre labels
-
Relationship type is preserved as IN_GENRE
-
The result is a bipartite graph of user genre preferences
Find users with similar genre preferences
Now that your users-genres projection is in place, you can run node similarity on it to create SIMILAR relationships between users who share genre preferences.
CALL gds.nodeSimilarity.write('users-genres', { // (1)
writeRelationshipType: 'SIMILAR', // (2)
writeProperty: 'score' // (3)
})
YIELD nodesCompared, relationshipsWritten // (4)
RETURN nodesCompared, relationshipsWritten // (5)Algorithm breakdown
-
Call node similarity in write mode on the 'users-genres' projection
-
Name the written relationship type
SIMILAR -
Store the similarity score on a
scoreproperty -
Yield the number of nodes compared and relationships written
-
Return those counts to confirm the write succeeded
With SIMILAR relationships now in your database, you can query them to find users who share genre tastes:
MATCH (u:User)-[:SIMILAR]-(u2:User) // (1)
WITH u.name AS name, collect(DISTINCT u2.name) AS similar_users_by_genre // (2)
RETURN name, similar_users_by_genre // (3)
LIMIT 100 // (4)Query breakdown
-
Match pairs of User nodes connected by SIMILAR relationships
-
Collect distinct similar user names for each user
-
Return user name and their list of similar users
-
Return only the top 100 rows
This query returns each user along with the users who share their genre preferences.
Check your understanding
Understanding The Projection Pattern
In the user-genre projection, what does a connection between a User and a Genre represent?
-
❏ The user created that genre
-
✓ The user rated at least one movie in that genre
-
❏ The user is an expert in that genre
-
❏ The user and genre share the same name
Hint
Remember the projection pattern traces through movies to connect users to genres.
Solution
The user rated at least one movie in that genre is correct.
The projection pattern User → RATED → Movie → IN_GENRE → Genre creates connections between users and genres when users have rated movies that belong to those genres. This bipartite structure reveals user genre preferences based on their rating behavior.
Benefits Of Label Preservation
You’ve created a user-genre projection with preserved labels. What advantage does this give you over a default projection?
-
❏ It uses less memory
-
❏ It runs algorithms faster
-
✓ You can run algorithms on only Users or only Genres by filtering node labels
-
❏ It automatically creates recommendations
Hint
Think about what the nodeLabels parameter allows you to do when calling algorithms.
Solution
You can run algorithms on only Users or only Genres by filtering node labels is correct.
When you preserve labels in your projection, you can use the nodeLabels configuration parameter:
CALL gds.degree.stream('users-genres', {
nodeLabels: ['Genre']
})This runs the algorithm only on Genre nodes, showing which genres have the most user connections. Without label preservation, you can’t make this distinction—all nodes are treated identically.
Summary
Creating multi-type projections with label preservation enables type-specific analysis and filtering. By preserving User and Genre labels, you can:
-
Run algorithms on specific node types
-
Filter results by label
-
Understand user preferences at the genre level
-
Build recommendation systems based on genre affinity
You’ve now completed the graph structure types series! You understand monopartite, bipartite, and multipartite graphs, and you can create GDS projections for each. Next, you’ll learn about the different categories of algorithms available in GDS.