Variable-length and shortest paths

Neo4j · Advanced · 15 min

Reachability, hierarchies and 'how are these connected' questions are where graph databases beat SQL most clearly.

When the number of hops is not fixed, use a quantified relationship: (a)-[:FOLLOWS]->{1,3}(b) matches paths of one to three FOLLOWS hops. + means one or more and * zero or more. The older syntax -[:FOLLOWS*1..3]-> still works but is not GQL-conformant.

Quantified path patterns (Cypher 5.9+) repeat a whole sub-pattern and can filter inside it:

MATCH (a:Stop)((x)-[r:NEXT]->(y) WHERE r.minutes < 10){1,5}(b:Stop)

Inside the group, variables become lists across the repetitions.

Assign a path to a variable with p = ... and use length(p), nodes(p) and relationships(p).

For shortest paths, Cypher 5.21+ supports SHORTEST k, ALL SHORTEST and SHORTEST k GROUPS in front of a path pattern; the older shortestPath() and allShortestPaths() functions remain. Shortest path here means fewest hops; weighted shortest paths (by distance or cost) come from Graph Data Science or APOC.

Always bound the length: an unbounded * or + over a dense graph can explore millions of paths. Use labels and relationship types, set an upper limit, and filter as early as possible.

Example

// everyone Ann can reach in 1 to 3 FOLLOWS hops, with the distance
MATCH p = (:Person {name: 'Ann'})-[:FOLLOWS]->{1,3}(x:Person)
RETURN x.name, min(length(p)) AS hops
ORDER BY hops;

// the shortest connection between Ann and Dan, any direction
MATCH p = SHORTEST 1 (a:Person {name: 'Ann'})-[:FOLLOWS]-+(d:Person {name: 'Dan'})
RETURN [n IN nodes(p) | n.name] AS route, length(p) AS hops;

// management chain upward, at most 10 levels
MATCH (e:Employee {name: 'Cy'})-[:REPORTS_TO]->{1,10}(boss:Employee)
RETURN collect(boss.name) AS chain;

Remember

  • -[:T]->{1,3}, + and * quantify hops; *1..3 is the legacy form
  • Quantified path patterns repeat sub-patterns with inline WHERE
  • SHORTEST k / shortestPath() find fewest-hop paths
  • Bound path lengths to avoid exploding traversals

Watch out for

  • Running an unbounded variable-length match on a dense graph and timing out.

Check yourself

  1. What does (a)-[:KNOWS]->{2,4}(b) match?

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

Official docs: neo4j.com/docs/cypher-manual/current/patterns/variable-length-patterns/