Skip to content

Conversation

@WilcoNeo
Copy link
Contributor

@WilcoNeo WilcoNeo commented Jan 8, 2025

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

@WilcoNeo WilcoNeo force-pushed the dev-document-shortestPath-function-lowerBound-restriction branch from 5295434 to d25c1ba Compare January 8, 2025 09:46
@blouerat blouerat self-assigned this Jan 9, 2025
@dogofbrian
Copy link
Contributor

As this is a rule, it should get a mention in the Rules section. It could be kept to a minimum e.g.

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

Then add another example under Not allowed e.g.shortestPath((a)-[:R*2..10]-(b))

@WilcoNeo WilcoNeo force-pushed the dev-document-shortestPath-function-lowerBound-restriction branch from 946efca to 148ec59 Compare January 10, 2025 08:39
@neo-technology-commit-status-publisher
Copy link
Collaborator

neo-technology-commit-status-publisher commented Jan 10, 2025

Thanks for the documentation updates.

The preview documentation has now been torn down - reopening this PR will republish it.

@JPryce-Aklundh JPryce-Aklundh added cherry-pick-this-to-5.x Cherry pick this PR changes to the 5.x branch cherry-pick-this-to-cypher-25 labels Jan 10, 2025
@JPryce-Aklundh JPryce-Aklundh merged commit 57ae186 into neo4j:dev Jan 10, 2025
5 checks passed
JPryce-Aklundh added a commit that referenced this pull request Jan 10, 2025
…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]>
JPryce-Aklundh added a commit that referenced this pull request Jan 10, 2025
…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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cherry-pick-this-to-5.x Cherry pick this PR changes to the 5.x branch dev team-cypher-planner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants