Skip to content

Commit

Permalink
Document lower bound restriction for shortestPath() and allShortestPa…
Browse files Browse the repository at this point in the history
…th() functions (#1146)

Document that the shortestPath() and allShortestPath() functions can
only have a lower bound of 0 or 1 for its variable length pattern.

This is not allowed:
` MATCH p=shortestPath((a:A)-[:R*2..]->(b:B)) RETURN 1`

A lower bound can be specified using a filter, but might lead to
executing a possibly very slow fallback plan.
` MATCH p=shortestPath((a:A)-[:R*]->(b:B)) WHERE length(p)>2 RETURN 1`

The possibly very slow fallback plan is this part:
```
| | +Top                   |  3 | anon_1 ASC LIMIT 1                                    |              1 | In Pipeline 6       |
| | |                      +----+-------------------------------------------------------+----------------+---------------------+
| | +Projection            |  4 | length(p) AS anon_1                                   |              1 |                     |
| | |                      +----+-------------------------------------------------------+----------------+                     |
| | +Filter                |  5 | length(p) > $autoint_0                                |              1 |                     |
| | |                      +----+-------------------------------------------------------+----------------+                     |
| | +Projection            |  6 | (a)-[anon_0*]->(b) AS p                               |              4 |                     |
| | |                      +----+-------------------------------------------------------+----------------+                     |
| | +VarLengthExpand(Into) |  7 | (a)-[anon_0:R*]->(b)                                  |              4 |                     |
| | |                      +----+-------------------------------------------------------+----------------+                     |
| | +Argument              |  8 | a, b                                                  |            100 | Fused in Pipeline 5 |
| |                        +----+-------------------------------------------------------+----------------+---------------------+

```

Within this query plan:
```
+--------------------------+----+-------------------------------------------------------+----------------+---------------------+
| Operator                 | Id | Details                                               | Estimated Rows | Pipeline            |
+--------------------------+----+-------------------------------------------------------+----------------+---------------------+
| +ProduceResults          |  0 | `1`                                                   |             30 |                     |
| |                        +----+-------------------------------------------------------+----------------+                     |
| +Projection              |  1 | $autoint_1 AS `1`                                     |             30 |                     |
| |                        +----+-------------------------------------------------------+----------------+                     |
| +AntiConditionalApply    |  2 |                                                       |             30 | Fused in Pipeline 7 |
| |\                       +----+-------------------------------------------------------+----------------+---------------------+
| | +Top                   |  3 | anon_1 ASC LIMIT 1                                    |              1 | In Pipeline 6       |
| | |                      +----+-------------------------------------------------------+----------------+---------------------+
| | +Projection            |  4 | length(p) AS anon_1                                   |              1 |                     |
| | |                      +----+-------------------------------------------------------+----------------+                     |
| | +Filter                |  5 | length(p) > $autoint_0                                |              1 |                     |
| | |                      +----+-------------------------------------------------------+----------------+                     |
| | +Projection            |  6 | (a)-[anon_0*]->(b) AS p                               |              4 |                     |
| | |                      +----+-------------------------------------------------------+----------------+                     |
| | +VarLengthExpand(Into) |  7 | (a)-[anon_0:R*]->(b)                                  |              4 |                     |
| | |                      +----+-------------------------------------------------------+----------------+                     |
| | +Argument              |  8 | a, b                                                  |            100 | Fused in Pipeline 5 |
| |                        +----+-------------------------------------------------------+----------------+---------------------+
| +Apply                   |  9 |                                                       |            100 |                     |
| |\                       +----+-------------------------------------------------------+----------------+---------------------+
| | +Optional              | 10 | a, b                                                  |            100 | In Pipeline 4       |
| | |                      +----+-------------------------------------------------------+----------------+---------------------+
| | +ShortestPath          | 11 | p = (a)-[anon_0:R*]->(b) WHERE length(p) > $autoint_0 |             30 |                     |
| | |                      +----+-------------------------------------------------------+----------------+                     |
| | +Argument              | 12 | a, b                                                  |            100 | Fused in Pipeline 3 |
| |                        +----+-------------------------------------------------------+----------------+---------------------+
| +CartesianProduct        | 13 |                                                       |            100 | In Pipeline 2       |
| |\                       +----+-------------------------------------------------------+----------------+---------------------+
| | +NodeByLabelScan       | 14 | b:B                                                   |             10 | In Pipeline 1       |
| |                        +----+-------------------------------------------------------+----------------+---------------------+
| +NodeByLabelScan         | 15 | a:A                                                   |             10 | In Pipeline 0       |
+--------------------------+----+-------------------------------------------------------+----------------+---------------------+
```

Better is to use the keyword-based SHORTEST.
`MATCH p = SHORTEST 1 (a:A)-[:R]->{2,}(b:B) RETURN 1`

---------

Co-authored-by: Jens Pryce-Åklundh <[email protected]>
  • Loading branch information
WilcoNeo and JPryce-Aklundh committed Jan 10, 2025
1 parent 4a92c13 commit 7af0652
Showing 1 changed file with 4 additions and 1 deletion.
5 changes: 4 additions & 1 deletion modules/ROOT/pages/patterns/reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,7 @@ They are similar to `SHORTEST 1` and `ALL SHORTEST`, but with several difference
* The path pattern is passed as an argument to the functions.
* The path pattern is limited to a single relationship pattern.
* To return results where the first and last node in the path are the same requires a change to the configuration setting link:{neo4j-docs-base-uri}/operations-manual/{page-version}/configuration/configuration-settings/#config_dbms.cypher.forbid_shortestpath_common_nodes[`dbms.cypher.forbid_shortestpath_common_nodes`].
* The minimum path length, also called the lower bound of the variable length relationship pattern, should be 0 or 1.

Both functions will continue to be available, but they are not xref:appendix/gql-conformance/index.adoc[GQL conformant].

Expand Down Expand Up @@ -1414,7 +1415,7 @@ shortestPath((:A)-->+(:B))
[[shortest-functions-rules-path-pattern-length]]
==== Path pattern length

There must be exactly one relationship pattern in the path pattern.
There must be exactly one relationship pattern in the path pattern, and the lower bound should be 0 or 1.

.Allowed
[source]
Expand All @@ -1427,6 +1428,8 @@ shortestPath((a)-[:R*1..5]-(b))
----
shortestPath((a)-[:R*1..5]-(b)-->(:X))
shortestPath((a)-[:R*2..5]-(b))
shortestPath((:A))
allShortestPaths((a:A)-[:S*]->(:B), (a)-[:R*1..3]->(:C))
Expand Down

0 comments on commit 7af0652

Please sign in to comment.