Graph data modelling

Neo4j · Advanced · 15 min

Model choices decide whether queries are one fast traversal or a slow scan, and they are hard to change later.

Graph modelling starts, like any design, from the questions the application asks. Sketch them as patterns, then choose structure:

  • Nodes for things you look up or connect to; relationships for verbs between them; properties for attributes you filter or return.
  • Make relationship types specific: (:Person)-[:LIVES_IN]->(:City) and -[:BORN_IN]-> beat a generic -[:RELATED {type:'lives'}]->, because traversals filter by type for free.
  • If a value is shared and queried across entities (a country, a genre, a skill), promote it to a node: "who else has this skill" becomes a one-hop traversal instead of a property scan.
  • Use an intermediate node when a relationship needs to connect more than two things or be referenced itself: an (:Employment) node linking person, company and role, or an (:Order) between customer and products.
  • Use labels for roles and categories you query by; avoid hundreds of labels with a handful of nodes each.
  • Time-based data: link events in order (:NEXT) or hang them off a time tree when range queries dominate.

Watch for supernodes, nodes with millions of relationships (a :Country node everyone lives in). Traversing through them is expensive; use more specific types, add direction, or remodel.

Refactor freely: Cypher can restructure a model in place, for example turning a property into nodes with MERGE.

Example

// before: skills as a list property, "who shares a skill" needs a scan
// (:Person {name: 'Ann', skills: ['cypher', 'python']})

// refactor: promote each skill to a node
MATCH (p:Person) WHERE p.skills IS NOT NULL
UNWIND p.skills AS skill
MERGE (s:Skill {name: skill})
MERGE (p)-[:HAS_SKILL]->(s)
REMOVE p.skills;

// now a short traversal
MATCH (:Person {name: 'Ann'})-[:HAS_SKILL]->(s)<-[:HAS_SKILL]-(peer)
RETURN peer.name, collect(s.name) AS shared
ORDER BY size(shared) DESC;

Remember

  • Model from the questions: nodes for things, relationships for verbs
  • Specific relationship types make traversals cheap
  • Promote shared values to nodes; use intermediate nodes for n-ary facts
  • Watch out for supernodes with huge degrees

Watch out for

  • Using a single generic relationship type with a 'type' property, losing the free filtering by type.

Check yourself

  1. Users often ask 'which people share a skill with me?'. How should skills be modelled?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: neo4j.com/docs/getting-started/data-modeling/