Paths with repeated nodes and relationships

By default, Cypher® does not allow relationships to be re-traversed in the same graph pattern match. This constraint can be bypassed using the REPEATABLE ELEMENTS keyword, which ensures there are no restrictions on how many times a node or relationship can occur for a given MATCH result.

The REPEATABLE ELEMENTS keyword must be specified after the MATCH clause.

Query using REPEATABLE ELEMENTS
MATCH REPEATABLE ELEMENTS p = (start)--{,2}(end)
RETURN p
REPEATABLE ELEMENTS is a GQL conformant match mode. Match modes determine whether relationships can appear more than once in a graph pattern match. For more information, see Syntax and semantics → Match modes.

Example graph

This page will use the scenario of the Seven bridges of Königsberg, a problem studied by Leonhard Euler in 1736 to determine if one could cross all seven bridges of Königsberg exactly once in a single walk.

To recreate the graph, run the following query against an empty Neo4j database:

CREATE (kneiphof:Location {name: "Kneiphof"}),
       (northBank:Location {name: "North Bank"}),
       (southBank:Location {name: "South Bank"}),
       (lomse:Location {name: "Lomse"}),

       (kneiphof)-[:BRIDGE {id: 1}]->(northBank),
       (kneiphof)-[:BRIDGE {id: 6}]->(southBank),
       (kneiphof)-[:BRIDGE {id: 7}]->(lomse),
       (northBank)-[:BRIDGE {id: 5}]->(kneiphof),
       (northBank)-[:BRIDGE {id: 2}]->(lomse),
       (southBank)-[:BRIDGE {id: 4}]->(kneiphof),
       (southBank)-[:BRIDGE {id: 3}]->(lomse)

REPEATABLE ELEMENTS and the Königsberg bridges problem

The section on Cypher’s default traversal rules and the Königsberg bridges problem showed the impossibility of crossing each of the seven bridges in Königsberg exactly once in a single walk.

REPEATABLE ELEMENTS does not solve this impossibility. However, the ability to re-traverse relationships does allow Cypher to return paths when testing Euler’s hypothesis.

The following query matches the graph for paths with a length of 7 relationships using REPEATABLE ELEMENTS and returns a sample path.

Find a path with a length of 7 relationships using REPEATABLE ELEMENTS
MATCH REPEATABLE ELEMENTS p = (:Location {name: 'Kneiphof'})-[:BRIDGE]-{7}()
WITH collect(p)[0] AS samplePath
RETURN [n IN nodes(samplePath) | n.name] AS samplePathLocations,
       [r IN relationships(samplePath) | r.id] AS samplePathBridges
Result
samplePathLocations samplePathBridges

["Kneiphof", "North Bank", "Kneiphof", "North Bank", "Kneiphof", "North Bank", "Kneiphof", "North Bank"]

[1, 5, 1, 5, 1, 5, 1]

Rows: 1

While no paths with a length of 7 can be returned using Cypher’s default MATCH behavior, the query now returns a samplePath that shows the same two bridges (1 and 5) being repeatedly re-traversed until the maximum path length is reached.

The next example matches paths starting and ending at the same Location (Kneiphof), where each bridge is crossed at least once, using REPEATABLE ELEMENTS:

Find a path traversing all bridges at least once before returning to the starting Location using REPEATABLE ELEMENTS
MATCH REPEATABLE ELEMENTS p = (start:Location {name: 'Kneiphof'})-[:BRIDGE]-{,9}(start) (1)
WHERE all(bridge IN range(1,7) WHERE bridge IN [r IN relationships(p) | r.id]) (2)
RETURN [n IN nodes(p) | n.name] AS visitedLocations,
       [r IN relationships(p) | r.id] AS crossedBridges
ORDER BY length(p), crossedBridges
LIMIT 1
1 Paths with a length of less than 9 relationships return no results because they do not allow enough moves to traverse all seven bridges at least once while forming a cycle back to Kneiphof.
2 The all() function ensures that each bridge must be traversed once in the path.
Result
visitedLocations crossedBridges

["Kneiphof", "North Bank", "Kneiphof", "South Bank", "Lomse", "North Bank", "Kneiphof", "South Bank", "Lomse", "Kneiphof"]

[1, 1, 4, 3, 2, 5, 6, 3, 7]

Rows: 1

The order of the bridges traversed in the path returned demonstrates that bridges 1 and 3 were crossed twice in order to return to Kneiphof.

Sequence of bridge traversals when using REPEATABLE ELEMENTS.

For more information about REPEATABLE ELEMENTS, see Syntax and semantics → Repeatable relationship and node matching.

Bounded path length

When using Cypher’s default MATCH behavior, the number of returned paths is limited because relationships cannot be re-traversed. However, because REPEATABLE ELEMENTS allows for re-traversing relationships, it enables full cycle re-traversals and paths that can double back on relationships. As a result, REPEATABLE ELEMENTS can generate a very large, or even infinite, number of valid paths.

The below query shows that there are 10583 valid paths with a length of 7 relationships starting from Kneiphof using REPEATABLE ELEMENTS:

Count the paths traversing all 7 bridges at least once using REPEATABLE ELEMENTS
MATCH REPEATABLE ELEMENTS p = (:Location {name: 'Kneiphof'})-[:BRIDGE]-{7}()
RETURN count(p) AS pathCount
Result
pathCount

10583

Rows: 1

If the path length is increased to exactly 10, a total of 490047 paths are returned, 11 hops returns 1818159 paths, 12 hops returns 6498397 paths, and so on, without limit.

To ensure that a MATCH will return a finite number of solutions in a finite amount of time, unbounded quantifiers that do not impose an upper bound on a pattern, such as *, +, or {1,} are not allowed in combination with REPEATABLE ELEMENTS. Also, users should take into account that the number of results returned for a high number of repetitions can significantly impact both memory usage and the speed of the query.

Not allowed: find paths of an unbounded length using REPEATABLE ELEMENTS
MATCH REPEATABLE ELEMENTS p = (start:Location {name: 'Kneiphof'})-[:BRIDGE]-+(start)
WHERE all(bridge IN range(1,7) WHERE bridge IN [r IN relationships(p) | r.id])
RETURN count(p) AS pathCount
GQLSTATUS error chain

42N53: error: syntax error or access rule violation - unsafe usage of repeatable elements. The quantified path pattern may yield an infinite number of rows under match mode 'REPEATABLE ELEMENTS'. Add an upper bound to the quantified path pattern.

42001: error: syntax error or access rule violation - invalid syntax