Chapter 04 · Advanced Pattern Matching: Variable Length, OPTIONAL MATCH, Paths, Quantified Patterns, and Shortest Paths
Shortest-Path Queries, Weighted vs Unweighted Reasoning, and When to Use Graph Data Science Instead
Define what “shortest” means before choosing syntax: fewest relationships, every minimum-hop tie, or a weighted positive-cost algorithm are different contracts.
Learning outcomes
AtlasMart wants the “shortest” operational route from a supplier to a store. That word is ambiguous: fewest handoffs, lowest minutes, lowest cost, or some multi-criteria score? Cypher path selectors and GDS path-finding algorithms answer different versions of that question.
Use current Cypher shortest-path selectors for unweighted hop-count questions.
Distinguish ANY SHORTEST from ALL SHORTEST and bounded arbitrary path enumeration.
Prove that fewer hops can have a higher relationship-cost total.
Identify when weighted positive-cost routing calls for GDS Dijkstra rather than Cypher hop-shortest.
Separate transactional one-query path lookup from projected analytical graph algorithms and their memory lifecycle.
Continue Chapters 01–03 with Neo4j Community
2026.07.1, database neo4j, explicit
CYPHER 25 in version-sensitive examples, local
container atlasmart-neo4j, Bolt
127.0.0.1:7687, HTTP 127.0.0.1:7474,
and constraint-backed AtlasMart domain identifiers. Chapter 04
adds a small synthetic operational handoff subgraph on
existing Supplier/Category/Store concepts; it is intentionally
isolated for path-mechanics exercises and does not replace the
transactional relationships modeled earlier.
Neo4j 2026.07.1 is the current 2026 release used
by this course snapshot; 5.26.30 remains the
current 5.26 LTS comparison line. The current manual covers
Cypher 25; Cypher 5 is frozen. Quantified path
patterns/relationships date from Neo4j 5.9, while explicit
Cypher 25 path modes such as ACYCLIC arrived
later and have version-sensitive combination rules. Commands
here were checked against current documentation but could not
be executed in this generation environment, so expected output
is described by deterministic invariants rather than
fabricated captures.
1. “Shortest” in Cypher path selectors is shortest by path length
CYPHER 25CREATE CONSTRAINT supplier_id IF NOT EXISTS FOR (s:Supplier) REQUIRE s.supplierId IS UNIQUE;CREATE CONSTRAINT category_id IF NOT EXISTS FOR (c:Category) REQUIRE c.categoryId IS UNIQUE;CREATE CONSTRAINT store_id IF NOT EXISTS FOR (s:Store) REQUIRE s.storeId IS UNIQUE;CREATE CONSTRAINT ops_point_id IF NOT EXISTS FOR (n:OpsPoint) REQUIRE n.pointId IS UNIQUE;MERGE (s1:Supplier {supplierId:'SUP-3001'}) SET s1:OpsPoint, s1.pointId='OP-SUP-1', s1.name='Northwind Optics';MERGE (s2:Supplier {supplierId:'SUP-3002'}) SET s2:OpsPoint, s2.pointId='OP-SUP-2', s2.name='Audio Forge';MERGE (c1:Category {categoryId:'CAT-CAMERAS'}) SET c1:OpsPoint, c1.pointId='OP-CAT-CAM', c1.name='Cameras';MERGE (c2:Category {categoryId:'CAT-AUDIO'}) SET c2:OpsPoint, c2.pointId='OP-CAT-AUD', c2.name='Audio';MERGE (st1:Store {storeId:'ST-001'}) SET st1:OpsPoint, st1.pointId='OP-ST-1', st1.name='Central', st1.region='west';MERGE (st2:Store {storeId:'ST-002'}) SET st2:OpsPoint, st2.pointId='OP-ST-2', st2.name='Harbor', st2.region='east';MERGE (st3:Store {storeId:'ST-003'}) SET st3:OpsPoint, st3.pointId='OP-ST-3', st3.name='Airport', st3.region='north';MATCH (s1:OpsPoint {pointId:'OP-SUP-1'}), (s2:OpsPoint {pointId:'OP-SUP-2'}), (c1:OpsPoint {pointId:'OP-CAT-CAM'}), (c2:OpsPoint {pointId:'OP-CAT-AUD'}), (st1:OpsPoint {pointId:'OP-ST-1'}), (st2:OpsPoint {pointId:'OP-ST-2'}), (st3:OpsPoint {pointId:'OP-ST-3'})MERGE (s1)-[:HANDOFF_TO {routeId:'R01', minutes:30, active:true}]->(st1)MERGE (s1)-[:HANDOFF_TO {routeId:'R02', minutes:10, active:true}]->(c1)MERGE (c1)-[:HANDOFF_TO {routeId:'R03', minutes:8, active:true}]->(st1)MERGE (c1)-[:HANDOFF_TO {routeId:'R04', minutes:5, active:true}]->(c2)MERGE (st1)-[:HANDOFF_TO {routeId:'R05', minutes:12, active:true}]->(s2)MERGE (st1)-[:HANDOFF_TO {routeId:'R06', minutes:11, active:false}]->(c2)MERGE (s2)-[:HANDOFF_TO {routeId:'R07', minutes:9, active:true}]->(c2)MERGE (s2)-[:HANDOFF_TO {routeId:'R08', minutes:6, active:true}]->(st2)MERGE (c2)-[:HANDOFF_TO {routeId:'R09', minutes:7, active:true}]->(st2)MERGE (st2)-[:HANDOFF_TO {routeId:'R10', minutes:14, active:true}]->(s1)MERGE (st2)-[:HANDOFF_TO {routeId:'R11', minutes:4, active:true}]->(st3)MERGE (st3)-[:HANDOFF_TO {routeId:'R12', minutes:13, active:true}]->(c1);
CYPHER 25MATCH (s:OpsPoint {pointId:'OP-SUP-1'}), (t:Store:OpsPoint {storeId:'ST-001'})MATCH p=ANY SHORTEST (s)-[:HANDOFF_TO]->{1,5}(t)RETURN length(p) AS hops, [n IN nodes(p) | n.pointId] AS points, reduce(total=0, r IN relationships(p) | total+r.minutes) AS minutes;
The fixture deliberately has a one-hop route
R01 costing 30 minutes and a two-hop route
R02 + R03 costing 18 minutes.
ANY SHORTEST should choose the one-hop route
because its selection criterion is path length. That is correct
for “fewest handoffs” and wrong for “least minutes.”
2. ANY SHORTEST and ALL SHORTEST answer different tie questions
CYPHER 25MATCH (s:OpsPoint {pointId:$source}), (t:OpsPoint {pointId:$target})MATCH p=ALL SHORTEST (s)-[:HANDOFF_TO]->{1,6}(t)RETURN length(p) AS hops, [r IN relationships(p) | r.routeId] AS routesORDER BY routes;
ANY SHORTEST can return one shortest path from a
partition; ALL SHORTEST returns every path tied for
shortest length. If tie identity matters to an API, choose
deliberately and supply deterministic ordering only after the
selector has defined the candidate set.
3. Enumerate-and-sort can demonstrate weighted semantics, not provide a scalable weighted algorithm
CYPHER 25MATCH (s:OpsPoint {pointId:'OP-SUP-1'}), (t:Store:OpsPoint {storeId:'ST-001'})MATCH p=(s)-[:HANDOFF_TO]->{1,4}(t)WITH p, reduce(total=0, r IN relationships(p) | total+r.minutes) AS minutesRETURN length(p) AS hops, [r IN relationships(p) | r.routeId] AS routes, minutesORDER BY minutes, hopsLIMIT 1;
This query is acceptable as a tiny deterministic teaching comparison because the bound and graph are small. It first matches candidate paths, calculates cost, sorts them, and only then keeps one. On a large dense graph, enumerating all bounded candidates may still be far more expensive than a purpose-built weighted shortest-path algorithm.
4. GDS Dijkstra is the optional weighted-learning path
Neo4j Graph Data Science runs algorithms against an in-memory projected graph catalog. Dijkstra source-target supports positive relationship weights. GDS is not required for this chapter’s mandatory Community lab, so the course first proves weighted semantics deterministically in Cypher, then shows the optional algorithm boundary.
// Requires a compatible GDS installation; not mandatory for Chapter 04.MATCH (source:OpsPoint)-[r:HANDOFF_TO]->(target:OpsPoint)RETURN gds.graph.project( 'atlasmart-handoff', source, target, {relationshipProperties: r {.minutes}});MATCH (source:OpsPoint {pointId:'OP-SUP-1'}), (target:Store:OpsPoint {storeId:'ST-001'})CALL gds.shortestPath.dijkstra.stream( 'atlasmart-handoff', {sourceNode:source, targetNodes:[target], relationshipWeightProperty:'minutes'})YIELD totalCost, pathRETURN totalCost, [n IN nodes(path) | n.pointId] AS points;CALL gds.graph.drop('atlasmart-handoff');
Always verify the exact GDS version/API before running. Estimate projection memory, scope labels/relationships, and drop temporary graphs. The GDS graph is an analytical in-memory projection, not an independent transactional source of truth.
5. Production decision table
| Question | Preferred starting mechanism | Why |
|---|---|---|
| Is target reachable within 4 hops? | Bounded MATCH or EXISTS subquery | Transactional, bounded boolean question. |
| Give me one path with fewest handoffs | ANY SHORTEST |
Restrictive hop-shortest selector. |
| Give every hop-shortest tie | ALL SHORTEST |
Preserves all minimum-hop alternatives. |
| Find least positive minutes/cost at scale | GDS Dijkstra / purpose-built weighted search | Cost property participates in algorithm instead of post-enumeration sort. |
| Repeated analytical routing across large graph | Projected GDS workflow after memory/refresh design | Separates analytical workload from ad-hoc transactional path enumeration. |
Production judgment includes graph freshness, edge-weight semantics, negative weights, projection cost, update cadence, memory, concurrency and whether the request must observe the latest committed transaction. Next, Chapter 04 closes by reproducing path explosion and systematically rewriting it.
Check your understanding
- What metric does ANY SHORTEST optimize in these Cypher path patterns?
- Why can the one-hop path be worse for AtlasMart?
- What does ALL SHORTEST add?
- Why is ORDER BY totalCost LIMIT 1 over all matched paths risky on a dense graph?
- What extra lifecycle does GDS introduce?
Review the answers
1. Path length/hop count.
2. Its relationship minutes can be higher than a longer-hop alternative.
3. All paths tied for minimum path length, rather than an arbitrary one of them.
4. The query may need to enumerate a huge candidate set before sorting and limiting.
5. An in-memory graph projection with memory estimation, refresh/freshness considerations, algorithm execution and cleanup.
Summary and next step
Shortest-Path Queries, Weighted vs Unweighted Reasoning, and When to Use Graph Data Science Instead is useful only when its assumptions and observed evidence stay attached to the decision. The examples above establish a reproducible mechanism and boundary; they do not turn one lab result into a universal production rule.
Next, continue to Diagnose a Path Explosion and Rewrite the Query with Better Anchors, Bounds, and Predicates. Carry forward the verified assumptions, fixture state, version/edition boundaries, and measurements from this lesson instead of treating the next topic as an isolated recipe.
Authoritative references
- Current Neo4j versions — Official current-release and 5.26 LTS patch snapshot.
- Cypher Manual introduction — Current Cypher 25 baseline and Cypher 5 compatibility framing.
- Patterns — Current graph/path matching overview, including shortest paths and match/path modes.
- Variable-length paths — Quantified path patterns, quantified relationships, group variables and inline predicates.
- Variable-length path reference — Formal syntax and rules for quantified and legacy variable-length patterns.
- Path-pattern reference — Path values, path-pattern composition and matching rules.
- Unique relationship paths — Default relationship-uniqueness behavior and DIFFERENT RELATIONSHIPS semantics.
- Match modes and path modes — Current Cypher 25 WALK/TRAIL/ACYCLIC and match-mode compatibility rules.
- OPTIONAL MATCH — Outer-row preservation and null introduction when a pattern is absent.
- WHERE — WHERE as a subclause of MATCH/OPTIONAL MATCH and its pattern-scoping consequences.
- Path functions — nodes(), relationships(), length()/path_length() and path-related list/predicate functions.
- Shortest paths — Current SHORTEST/ALL SHORTEST path selector semantics.
- Query plans and operators — Execution-plan operators and row/db-hit/memory evidence.
- GDS graph algorithms — Graph Data Science algorithm families including path finding.
- GDS Dijkstra source-target — Weighted positive-edge shortest-path algorithm for projected GDS graphs.