Reputation: 53881
I want to make IMDB's characters/roles structure in Neo4j. I'll need labels Person
, Movie
and Character
. Character
, because a character can be in multiple movies, played by different people.
Without Character
, it's easy:
(Person)-[:PLAYS_IN]->(Movie)
But PLAYS_IN
is a Character
, so it would be something like:
(Person)-[:PLAYS_AS]->(Character)-[:PLAYS_IN]->(Movie)
but that doesn't work, because it doesn't have a direct Person-Movie
relationship. Without that, everyone who ever played Peter Parker, is in every movie that has a Peter Parker.
There must be a Person-Movie relationship, but also a Person-Movie-Character relationship. How? This could work, but that's just nasty:
(Person)-[:PLAYS_IN {uuid}]->(Movie), (Character {uuid})
because now I'm creating my own foreign key kind of relationship. That's very ungraphdb. But it works:
MATCH (p:Person)-[r:PLAYS_IN]->(m:Movie), (c:Character)
WHERE c.uuid = r.uuid
RETURN p, c, m
by building a cartesian product =( which is very RDBMS, but not very graphdb. And I can't query Character-Movie
or Character-Person
, because that's not a real relationship.
How do I make a RDBMS link table with 3 foreign keys (movie_id, character_id, person_id
) in Neo4j??
edit 1
The RDBMS equivalent:
movies (id, title) # e.g. Dragon Tattoo, or Spider's Web
people (id, name) # e.g. Rooney Mara, or Claire Foy
characters (id, name) # e.g. Lisbeth Salander
roles (movie_id, person_id, character_id) # 2 rows with 1 distinct character_id
Upvotes: 2
Views: 270
Reputation: 29167
Your problem is solved by hypergraphs. But since neo4j does not support hypergraphs, you need to model them. For example:
CREATE (P1:Person {name: 'Tobey Maguire'})
CREATE (P2:Person {name: 'Nicholas Hammond'})
CREATE (CW1:CreativeWork {name: 'Spider-Man'})
CREATE (CW2:CreativeWork {name: 'The Amazing Spider-Man (TV Series)'})
CREATE (CH:Character {name: 'Spider-Man'})
CREATE (A1:Role)
CREATE (A2:Role)
CREATE (P1)-[:PLAYS_AS]->(A1)
CREATE (A1)-[:HAS_CHARACTER]->(CH)
CREATE (A1)-[:PLAYS_IN]->(CW1)
CREATE (P2)-[:PLAYS_AS]->(A2)
CREATE (A2)-[:HAS_CHARACTER]->(CH)
CREATE (A2)-[:PLAYS_IN]->(CW2)
Upvotes: 3
Reputation: 1304
Make your relationship between Actor
and Movie
a rich relationship, where an Actor
who PLAYED_IN
a Movie
plays a specific Role
. The Role
is implemented as a separate entity (relationship entity) with its own properties and only becomes an entity when the relationship between Actor
and Movie
exists.
@NodeEntity
public class Actor {
Long id;
@Relationship(type="PLAYED_IN") private Role playedIn;
}
@RelationshipEntity(type = "PLAYED_IN")
public class Role {
@Id @GeneratedValue private Long relationshipId;
@Property private String title;
@StartNode private Actor actor;
@EndNode private Movie movie;
}
@NodeEntity
public class Movie {
private Long id;
private String title;
}
(token from the mentioned link)
Upvotes: 1