You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: cip/1.accepted/CIP2017-02-06-Regular-Path-Patterns.adoc
+79-77
Original file line number
Diff line number
Diff line change
@@ -17,83 +17,88 @@ In Cypher Regular Path Queries are expressed through the use of _Regular Path Pa
17
17
A Regular Path Pattern is defined as:
18
18
19
19
• A simple relationship type +
20
-
`()-/:X/-()` denotes a Regular Path Pattern matching relationships of type `X`.
20
+
`()-[:X]-()` denotes a Regular Path Pattern matching relationships of type `X`.
21
21
• A predicate on the labels of a node +
22
-
`()-/(:Z)/-()` denotes a Regular Path Pattern matching nodes with label `Z`.
22
+
`()-[(:Z)]-()` denotes a Regular Path Pattern matching nodes with label `Z`.
23
23
• A sequence of Regular Path Patterns +
24
-
`()-/_a_ _b_/-()` denotes a Regular Path Pattern matching first the pattern defined by `_a_`, then the pattern defined by `_b_` (in order left to right).
24
+
`()-[_a_ _b_]-()` denotes a Regular Path Pattern matching first the pattern defined by `_a_`, then the pattern defined by `_b_` (in order left to right).
25
25
• An alternative between Regular Path Patterns +
26
-
`()-/_a_ | _b_/-()` denotes a Regular Path Pattern matching either the pattern defined by `_a_` or the pattern defined by `_b_`.
26
+
`()-[_a_ | _b_]-()` denotes a Regular Path Pattern matching either the pattern defined by `_a_` or the pattern defined by `_b_`.
27
27
• A repetition of a Regular Path Pattern +
28
-
`()-/_a_*/-()` denotes a Regular Path Pattern matching the pattern defined by `_a_` zero or more times. +
29
-
`()-/_a_+/-()` denotes a Regular Path Pattern matching the pattern defined by `_a_` one or more times. +
30
-
`()-/_a_*_x_../-()` denotes a Regular Path Pattern matching the pattern defined by `_a_` `_x_` or more times. +
31
-
`()-/_a_*_x_.._y_/-()` denotes a Regular Path Pattern matching the pattern defined by `_a_` at least `_x_` times and at most `_y_` times.
28
+
`()-[_a_*]-()` denotes a Regular Path Pattern matching the pattern defined by `_a_` zero or more times. +
29
+
`()-[_a_+]-()` denotes a Regular Path Pattern matching the pattern defined by `_a_` one or more times. +
30
+
`()-[_a_*_x_..]-()` denotes a Regular Path Pattern matching the pattern defined by `_a_` `_x_` or more times. +
31
+
`()-[_a_*_x_.._y_]-()` denotes a Regular Path Pattern matching the pattern defined by `_a_` at least `_x_` times and at most `_y_` times.
32
32
• A grouping of a Regular Path Pattern +
33
-
`()-/[_a_]/-()` denotes a grouping of the pattern `_a_`.
33
+
`()-[[_a_]]-()` denotes a grouping of the pattern `_a_`.
34
34
• A specification of direction for a Regular Path Pattern +
35
-
`()-/ _a_ >/-()` denotes that the Regular Path Pattern `_a_` should be interpreted in a left-to-right direction. +
36
-
`()-/< _a_ /-()` denotes that the Regular Path Pattern `_a_` should be interpreted in a right-to-left direction. +
37
-
`()-/< _a_ >/-()` denotes that the Regular Path Pattern `_a_` should be interpreted in any direction.
35
+
`()-[ _a_ >]-()` denotes that the Regular Path Pattern `_a_` should be interpreted in a left-to-right direction. +
36
+
`()-[< _a_ ]-()` denotes that the Regular Path Pattern `_a_` should be interpreted in a right-to-left direction. +
37
+
`()-[< _a_ >]-()` denotes that the Regular Path Pattern `_a_` should be interpreted in any direction.
38
38
• A reference to a Defined Path Predicate +
39
-
`()-/alpha/-()` denotes a reference to a Defined Path Predicate named `alpha`.
39
+
`()-[alpha]-()` denotes a reference to a Defined Path Predicate named `alpha`.
40
40
41
-
Regular Path Patterns are written similarly to how relationship patterns are written, but enclosed within two slash (`/`) characters instead of brackets (`[]`).
42
-
43
-
Contrary to Relationship Patterns, Regular Path Patterns do _not_ allow binding a relationship to a variable.
44
-
In order to bind the matching path to a variable, a Path Assignment should be used, by preceding the path with an identifier and an equals sign (`=`).
45
-
This avoids a problem that existed in the past with repetition of relationships (a syntax that is deprecated with the introduction of Regular Path Patterns), where a relationship variable would bind to a list, making it hard to express predicates over the actual relationships.
41
+
Binding of a relationship to a variable is only allowed in the most simple case of a Path Pattern, where only a single relationship is matched by the pattern.
42
+
For binding a whole path to a variable, Path Assignment should be used, by preceding the path with an identifier and an equals sign (`=`).
43
+
This avoids a problem that existed in the past with repetition of relationships (a syntax that is unsupported as of the introduction of Regular Path Patterns), where a relationship variable would bind to a list, making it hard to express predicates over the actual relationships.
46
44
Predicates on parts of a Regular Path Pattern are instead expressed through the use of explicitly defined path predicates.
47
45
48
46
=== Syntax
49
47
50
-
The syntax of Regular Path Patterns fit into the greater Cypher syntax through `PatternElementChain`.
48
+
Regular Path Patterns are part of the Pattern syntax of Cypher.
The direction of relationships matched by a Regular Path Pattern is primarily decided by the directional arrow surrounding the pattern.
94
-
If the arrow points from left to right (i.e. `(left)-/pattern/\->(right)`), the paths described by the pattern are paths in the left-to-right direction, i.e. paths that are _outgoing_ from the node to the left of the pattern, and _incoming_ to the node to the right of the pattern.
95
-
If the arrow points from right to left (i.e. `(left)\<-/pattern/-(right)`), the paths described by the pattern are paths in the right-to-left paths direction, i.e. paths that are _incoming_ to the node to the left of the pattern, and _outgoing_ from the node to the right of the pattern.
96
-
If there are no arrowheads (i.e. `(left)-/pattern/-(right)`), or if both arrowheads are present (i.e. `(left)\<-/pattern/\->(right)`), the paths described by the pattern are paths in either the left-to-right or the right-to-left direction.
99
+
If the arrow points from left to right (i.e. `(left)-[pattern]\->(right)`), the paths described by the pattern are paths in the left-to-right direction, i.e. paths that are _outgoing_ from the node to the left of the pattern, and _incoming_ to the node to the right of the pattern.
100
+
If the arrow points from right to left (i.e. `(left)\<-[pattern]-(right)`), the paths described by the pattern are paths in the right-to-left paths direction, i.e. paths that are _incoming_ to the node to the left of the pattern, and _outgoing_ from the node to the right of the pattern.
101
+
If there are no arrowheads (i.e. `(left)-[pattern]-(right)`), or if both arrowheads are present (i.e. `(left)\<-[pattern]\->(right)`), the paths described by the pattern are paths in either the left-to-right or the right-to-left direction.
97
102
98
103
All parts of a Regular Path Pattern will assume the direction of the surrounding arrow, unless the direction is explicitly overridden for that particular part of the pattern.
99
104
A prefix of `<` to part of a pattern overrides the direction of that part to be right-to-left.
@@ -103,7 +108,7 @@ Direction overrides only apply to a single pattern part.
103
108
In order to apply the direction override to multiple parts of the pattern, those parts should be grouped.
104
109
105
110
Using both a `<` prefix and a `>` suffix on the same pattern is always the same thing as a disjunction between that pattern with a `<` prefix and that pattern with a `>` suffix.
106
-
This means that `()-/< _a_ >/-()` is the same as `()-/[< _a_] | [_a_ >]/-()`.
111
+
This means that `()-[< _a_ >]-()` is the same as `()-[[< _a_] | [_a_ >]]-()`.
107
112
108
113
==== Directions and Defined Path Predicates
109
114
@@ -116,63 +121,60 @@ A Defined Path Predicate declared without a direction must have a definition tha
116
121
117
122
==== Direction examples
118
123
119
-
• `()-/a <[b c] d/\->()` is the same as `()-/a/\->()\<-/b c/-()-/d/\->(d)`, i.e. the direction of the group `b c` has been overridden to be right-to-left in a pattern where the overall direction is left-to-right.
120
-
• `()-/a <b> c/\->()` is the same as `()-/a/\->()-/b/-()-/c/\->()`, i.e. the direction of `b` has been overridden to be _either direction_.
121
-
• `()-/a/-()`, `()-/<a>/-()`, `()-/<a>/\->()`, `()\<-/<a>/-()`, `()\<-/<a>/\->()`, and `()\<-/a/\->()` all mean the same thing: matching `a` in _either direction_.
124
+
• `()-[a <[b c] d]\->()` is the same as `()-[a]\->()\<-[b c]-()-[d]\->(d)`, i.e. the direction of the group `b c` has been overridden to be right-to-left in a pattern where the overall direction is left-to-right.
125
+
• `()-[a <b> c]\->()` is the same as `()-[a]\->()-[b]-()-[c]\->()`, i.e. the direction of `b` has been overridden to be _either direction_.
126
+
• `()-[a]-()`, `()-[<a>]-()`, `()-[<a>]\->()`, `()\<-[<a>]-()`, `()\<-[<a>]\->()`, and `()\<-[a]\->()` all mean the same thing: matching `a` in _either direction_.
122
127
123
128
Given these Defined Path Predicates:
124
129
125
130
[source, cypher]
126
131
----
127
-
PATH (l)-/alpha/->(r) IS (l)-[:X]->()-[:Y]->(r)
128
-
PATH (l)-/beta/->(r) IS (l)<-[:Y]-()<-[:X]-(r)
129
-
PATH (l)-/gamma/-(r) IS (l)-/[:X :Y]> | <[:Y :X]/-(r)
132
+
PATH (l)-[alpha]->(r) IS (l)-[:X]->()-[:Y]->(r)
133
+
PATH (l)-[beta]->(r) IS (l)<-[:Y]-()<-[:X]-(r)
134
+
PATH (l)-[gamma]-(r) IS (l)-[[:X :Y]> | <[:Y :X]]-(r)
130
135
----
131
136
132
-
• `()-/alpha/\->()` is equivalent to `()\<-/beta/-()`
133
-
• `()\<-/alpha/-()` is equivalent to `()-/beta/\->()`
134
-
• `()-/gamma/\->()` is equivalent to `()\<-/gamma/-()`, since both are equivalent to `()-/gamma/-()`
135
-
• `()-/gamma/-()` is equivalent to `()-/alpha/-()`, since `()-/alpha/-()` is the same as `()-/alpha> | <alpha/-()`, which is equivalent to the declaration of `gamma`. +
136
-
It is also equivalent to `()-/<beta | beta>/-()` which is the same as `()-/beta/-()`.
137
+
• `()-[alpha]\->()` is equivalent to `()\<-[beta]-()`
138
+
• `()\<-[alpha]-()` is equivalent to `()-[beta]\->()`
139
+
• `()-[gamma]\->()` is equivalent to `()\<-[gamma]-()`, since both are equivalent to `()-[gamma]-()`
140
+
• `()-[gamma]-()` is equivalent to `()-[alpha]-()`, since `()-[alpha]-()` is the same as `()-[alpha> | <alpha]-()`, which is equivalent to the declaration of `gamma`. +
141
+
It is also equivalent to `()-[<beta | beta>]-()` which is the same as `()-[beta]-()`.
137
142
138
143
=== Regular Path Pattern Examples
139
144
140
145
The astute reader of the syntax will have noticed that it is possible to express a Regular Path Pattern with an empty path expression:
141
146
142
147
[source, cypher]
143
148
----
144
-
MATCH (a)-//-(b)
149
+
MATCH (a)-[]-(b)
145
150
----
146
151
147
-
This pattern simply states that `a` and `b` must be the same node, and is thus the same as:
148
-
149
-
[source, cypher]
150
-
----
151
-
MATCH (a), (b) WHERE a = b
152
-
----
152
+
The semantics of this query is to match any single relationship between `a` and `b`.
153
+
It is thus equivalent to `(a)-[-]-(b)` or `(a)--(b)`.
153
154
154
-
The same reader will also have noticed that it is possible to define a pattern containing just a relationship type:
155
+
It is possible to express a completely empty pattern, a pattern that matches `a` and `b` to the same node.
156
+
This is done by using only a single node predicate in the path pattern:
155
157
156
158
[source, cypher]
159
+
.A pattern matching a path of length 0
157
160
----
158
-
MATCH (a)-/:KNOWS/->(b)
161
+
MATCH (a)-[()]-(b)
159
162
----
160
163
161
-
That pattern is indeed equivalent to the very similar relationship pattern:
164
+
This pattern states that `a` and `b` must be the same node, by virtue of stating a pattern that matches any node.
165
+
It is thus the same as:
162
166
163
167
[source, cypher]
164
168
----
165
-
MATCH (a)-[:KNOWS]->(b)
169
+
MATCH (a), (b) WHERE a = b
166
170
----
167
171
168
-
The main difference being that the variant with a relationship pattern is able to bind that relationship and express further predicates over it.
169
-
170
172
The Regular Path Patterns start becoming interesting when larger expressions are put together:
171
173
172
174
[source, cypher]
173
175
.Finding someone loved by someone hated by someone you know, transitively
174
176
----
175
-
MATCH (you)-/[:KNOWS :HATES]+ :LOVES/->(someone)
177
+
MATCH (you)-[[:KNOWS :HATES]+ :LOVES]->(someone)
176
178
----
177
179
178
180
Note the `+` expressing one or more occurrences of the sequence `KNOWS` followed by `HATES`.
@@ -185,7 +187,7 @@ It is possible to both prefix the part with `<` and suffix it with `>`, indicati
185
187
[source, cypher]
186
188
.Specifying the direction for different parts of the pattern
187
189
----
188
-
MATCH (you)-/[:KNOWS <:HATES]+ :LOVES/->(someone)
190
+
MATCH (you)-[[:KNOWS <:HATES]+ :LOVES]->(someone)
189
191
----
190
192
191
193
In the example above we say that the `HATES` relationships should have the opposite direction to the other relationships in the path.
@@ -195,8 +197,8 @@ Through the use of Defined Path Predicates we can express even more predicates o
195
197
[source, cypher]
196
198
.Find a chain of unreciprocated lovers
197
199
----
198
-
MATCH (you)-/unreciprocated_love*/->(someone)
199
-
PATH (a)-/unreciprocated_love/->(b) IS
200
+
MATCH (you)-[unreciprocated_love*]->(someone)
201
+
PATH (a)-[unreciprocated_love]->(b) IS
200
202
(a)-[:LOVES]->(b)
201
203
WHERE NOT EXISTS { (b)-[:LOVES]->(a) }
202
204
----
@@ -209,8 +211,8 @@ This can be achieved by using a Defined Path Predicate where the nodes on both e
209
211
[source, cypher]
210
212
.Find friends of friends that are not haters
211
213
----
212
-
MATCH (you)-/:KNOWS not_a_hater :KNOWS/-(friendly_friend_of_friend)
213
-
PATH (x)-/not_a_hater/-(x) IS (x)
214
+
MATCH (you)-[:KNOWS not_a_hater :KNOWS]-(friendly_friend_of_friend)
215
+
PATH (x)-[not_a_hater]-(x) IS (x)
214
216
WHERE NOT EXISTS { (x)-[:HATES]->() }
215
217
----
216
218
@@ -222,8 +224,8 @@ This is obviously the case when both nodes are the same, but it would also be th
0 commit comments