Practice multipartite projection

Introduction

Now that you understand bipartite and multipartite graphs, it’s time to practice creating projections that preserve multiple node types.

In this lesson, you’ll work with the Movies dataset to create various bipartite projections and run node similarity on them—the same algorithm you used in the previous lesson.

By the end of this lesson, you will be able to:

  • Create bipartite projections with preserved labels

  • Run node similarity on different bipartite structures

  • Understand how projection patterns affect algorithm results

The movies dataset

Your database contains:

  • Actor nodes with properties like name and born

  • Movie nodes with properties like title and released

  • User nodes with properties like name

  • Genre nodes with properties like name

  • ACTED_IN relationships (Actor → Movie)

  • RATED relationships (User → Movie)

  • IN_GENRE relationships (Movie → Genre)

Projection 1: User-movie bipartite

Remember this projection you created in the previous lesson? Run this command again to create a bipartite user-movie network:

cypher
Project user-movie bipartite graph
MATCH (source:User)-[r:RATED]->(target:Movie) // (1)
WITH gds.graph.project( // (2)
  'user-movie', // (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)
  1. Match User nodes connected to Movie nodes via RATED relationships

  2. Call the GDS projection function

  3. Name the projection 'user-movie'

  4. Include source (User) nodes

  5. Include target (Movie) nodes

  6. Preserve source node labels

  7. Preserve target node labels

  8. Preserve relationship types

  9. Return projection statistics

This projection creates:

  • A bipartite network with User and Movie labels preserved

  • Users connected to movies through RATED relationships

  • A structure perfect for node similarity

In this lesson, you’ll use .write() mode to persist algorithm results to your database. Module 3 will teach all execution modes in detail—for now, follow the patterns shown in each example.

Now run node similarity on this projection:

cypher
Run node similarity on user-movie
CALL gds.nodeSimilarity.write( // (1)
  'user-movie', // (2)
  {
    writeRelationshipType: 'SIMILAR', // (3)
    writeProperty: 'score' // (4)
  })
YIELD nodesCompared, relationshipsWritten // (5)
  1. Call node similarity algorithm in write mode

  2. Run on 'user-movie' projection

  3. Write new relationships with type 'SIMILAR'

  4. Write similarity scores as 'score' property

  5. Yield the number of nodes compared and relationships written

Remember from the previous lesson: node similarity connects nodes on the same side of the bipartite graph.

Verify the results:

cypher
View similar users
MATCH path = (:User)-[:SIMILAR]->(:User)-[:SIMILAR]-(:User) // (1)
RETURN path // (2)
LIMIT 10 // (3)
  1. Match a path of users connected by SIMILAR relationships

  2. Return the complete path

  3. Limit to 10 results

What this reveals: Users with similar movie rating patterns.

Actor-Movie Bipartite

Now, let’s create a different bipartite projection: actors and movies with preserved labels.

Copy the code below into the query window and replace ???? with the correct values.

cypher
Complete the actor-movie projection (replace ????)
MATCH (source:????)-[r:????]->(target:????) // (1)
WITH ????( // (2)
  'actor-movie', // (3)
  source, // (4)
  target, // (5)
  {
    ????, // (6)
    ????, // (7)
    ???? // (8)
  },
  {}
) AS g
RETURN g.graphName AS graph, g.nodeCount AS nodes, g.relationshipCount AS rels // (9)
  1. Match Actor nodes connected to Movie nodes (fill in the labels and relationship)

  2. Call the GDS projection function (fill in function name)

  3. Name the projection 'actor-movie'

  4. Include source nodes

  5. Include target nodes

  6. Preserve source node labels (fill in configuration)

  7. Preserve target node labels (fill in configuration)

  8. Preserve relationship types (fill in configuration)

  9. Return projection statistics

If you need help finding the solution, you’ll find the full projection command in the dropdown below:

Details
cypher
Solution: Project actor-movie bipartite graph
MATCH (source:Actor)-[r:ACTED_IN]->(target:Movie) // (1)
WITH gds.graph.project( // (2)
  'actor-movie', // (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)
  1. Match Actor nodes connected to Movie nodes via ACTED_IN relationships

  2. Call the GDS projection function

  3. Name the projection 'actor-movie'

  4. Include source (Actor) nodes

  5. Include target (Movie) nodes

  6. Preserve source node labels

  7. Preserve target node labels

  8. Preserve relationship types

  9. Return projection statistics

This projection creates:

  • A bipartite network with Actor and Movie labels preserved

  • Actors connected to movies through ACTED_IN relationships

Now run node similarity on this projection.

cypher
Run node similarity on actor-movie
CALL gds.nodeSimilarity.write( // (1)
  'actor-movie', // (2)
  {
    writeRelationshipType: 'SIMILAR', // (3)
    writeProperty: 'score' // (4)
  })
YIELD nodesCompared, relationshipsWritten // (5)
  1. Call node similarity algorithm in write mode

  2. Run on 'actor-movie' projection

  3. Write new relationships with type 'SIMILAR'

  4. Write similarity scores as 'score' property

  5. Yield the number of nodes compared and relationships written

Verify the results:

cypher
View similar actors
MATCH path = (:Actor)-[:SIMILAR]->(:Actor)-[:SIMILAR]->(:Actor) // (1)
RETURN path // (2)
LIMIT 10 // (3)
  1. Match a path of actors connected by SIMILAR relationships

  2. Return the complete path

  3. Limit to 10 results

What this reveals: Actors who collaborate.

Movie-genre bipartite

Now create a bipartite projection of movies and genres, then run node similarity on it—this time, complete both steps yourself.

Step 1: Create the projection by replacing the ????? placeholders:

cypher
Complete the movie-genre projection (replace ?????)
MATCH (source:?????)-[r:?????]->(target:?????) // (1)
WITH ????( // (2)
  '?????', // (3)
  source, // (4)
  target, // (5)
  {
    ????, // (6)
    ????, // (7)
    ???? // (8)
  },
  {}
) ???? // (9)
RETURN ????, ????, ???? // (10)
  1. Match Movie nodes connected to Genre nodes (fill in the labels and relationship)

  2. Call the GDS projection function (fill in function name)

  3. Name the projection (choose a descriptive name)

  4. Include source nodes

  5. Include target nodes

  6. Preserve source node labels (fill in configuration)

  7. Preserve target node labels (fill in configuration)

  8. Preserve relationship types (fill in configuration)

  9. Alias the projection result (fill in alias)

  10. Return projection statistics (fill in return fields)

Step 2: Run node similarity on your projection. Replace the graph name and choose a relationship type:

cypher
Run node similarity on movie-genre
CALL gds.nodeSimilarity.write( // (1)
  'movie-genre', // (2)
  {
    writeRelationshipType: 'SIMILAR', // (3)
    writeProperty: 'score' // (4)
  })
YIELD nodesCompared, relationshipsWritten // (5)
  1. Call node similarity algorithm in write mode

  2. Run on 'movie-genre' projection

  3. Write new relationships with type 'SIMILAR'

  4. Write similarity scores as 'score' property

  5. Yield the number of nodes compared and relationships written

If you need to see the full command, feel free to open the dropdown below.

Details

Step 1: Create the projection

cypher
Solution: Project movie-genre bipartite graph
MATCH (source:Movie)-[r:IN_GENRE]->(target:Genre) // (1)
WITH gds.graph.project( // (2)
  'movie-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)
  1. Match Movie nodes connected to Genre nodes via IN_GENRE relationships

  2. Call the GDS projection function

  3. Name the projection 'movie-genre'

  4. Include source (Movie) nodes

  5. Include target (Genre) nodes

  6. Preserve source node labels

  7. Preserve target node labels

  8. Preserve relationship types

  9. Return projection statistics

Key points:

  • Match Movie nodes to Genre nodes via IN_GENRE relationships

  • Name the projection 'movie-genre'

  • Preserve labels with labels(source) and labels(target)

  • Run nodeSimilarity.write with 'SIMILAR' as the relationship type

Check which movies are similar based on shared genres:

cypher
View similar movies
MATCH (m1:Movie)-[s:SIMILAR]->(m2:Movie) // (1)
RETURN m1.title, m2.title, s.score // (2)
ORDER BY s.score DESC // (3)
LIMIT 10 // (4)
  1. Match pairs of Movie nodes connected by SIMILAR relationships

  2. Return the titles of both movies and their similarity score

  3. Sort by score in descending order

  4. Limit to top 10 most similar pairs

What this reveals: Movies that belong to similar genre combinations.

Comparing algorithm results

Each bipartite projection you created produces different node similarity results because the structure determines what "similarity" means.

User-Movie projection: Similarity is based on shared movie ratings (collaborative filtering)

Actor-Movie projection: Similarity is based on shared cast members (collaboration patterns)

Movie-Genre projection: Similarity is based on shared genre classifications (content-based similarity)

The same algorithm—node similarity—reveals completely different insights depending on your projection structure.

Understanding bipartite and multipartite graphs helps you design projections that answer specific analytical questions.

What’s next

You’ve now practiced creating multiple bipartite projections from the Movies dataset and running node similarity on each one—consolidating your understanding of how label preservation enables different types of analysis.

Each projection transformed the same data into different analytical contexts:

  • User-Movie (collaborative filtering)

  • Actor-Movie (collaboration patterns)

  • Movie-Genre (content-based similarity)

In the next lesson, you’ll put this knowledge to the test with a challenge that requires you to create your own bipartite projection and run node similarity independently.

Check your understanding

How Projections Affect Similarity

You ran node similarity on three different bipartite projections: User-Movie, Actor-Movie, and Movie-Genre.

Why did each projection produce different similarity results?

  • ✓ The projection structure determines what "similarity" means—shared ratings vs. shared cast vs. shared genres

  • ❏ Node similarity uses different algorithms depending on the node types in the projection

  • ❏ The three projections had different numbers of nodes, changing the algorithm’s behavior

  • ❏ GDS automatically adjusts similarity calculations based on the relationship types

Hint

Think about what node similarity does: it connects nodes that have shared neighbors. What are the neighbors in each projection?

Solution

The projection structure determines what "similarity" means—shared ratings vs. shared cast vs. shared genres.

Node similarity always does the same thing: it connects nodes on the same side of a bipartite graph based on shared neighbors on the other side.

However, what those neighbors represent changes the meaning of similarity:

  • User-Movie: Users are similar if they rated the same movies (collaborative filtering)

  • Actor-Movie: Actors are similar if they appeared in the same movies (collaboration patterns)

  • Movie-Genre: Movies are similar if they belong to the same genres (content-based similarity)

The algorithm doesn’t change—the analytical context does. This is why thoughtful projection design is fundamental to GDS work.

Summary

Bipartite projections with preserved labels enable node similarity to connect nodes on the same side of the graph based on shared neighbors.

You practiced creating three bipartite projections:

  • User-Movie: Found similar users based on rating patterns

  • Actor-Movie: Found similar actors based on collaboration patterns

  • Movie-Genre: Found similar movies based on genre classifications

The same algorithm—node similarity—reveals completely different insights depending on your projection structure. Understanding how to design meaningful bipartite projections is a fundamental GDS skill for relationship inference and recommendation systems.

Chatbot

How can I help you today?