提交 4fcebe54 编写于 作者: L Lars Korduner 提交者: Bastien Louërat

Added rewriter for shortestPath and allShortestPaths with a fixed length...

Added rewriter for shortestPath and allShortestPaths with a fixed length relationship to have a variable length of 1.
上级 5b5416d0
......@@ -956,7 +956,7 @@ class StatementConvertersTest extends CypherFunSuite with LogicalPlanningTestSup
query.queryGraph.patternNodes should equal(Set("a", "b"))
query.queryGraph.shortestPathPatterns should equal(Set(
ShortestPathPattern(Some("anon_0"), PatternRelationship("r", ("a", "b"), OUTGOING, Seq.empty, SimplePatternLength), single = true)(null)
ShortestPathPattern(Some("anon_0"), PatternRelationship("r", ("a", "b"), OUTGOING, Seq.empty, VarPatternLength(1, Some(1))), single = true)(null)
))
query.tail should be(empty)
}
......@@ -966,7 +966,7 @@ class StatementConvertersTest extends CypherFunSuite with LogicalPlanningTestSup
query.queryGraph.patternNodes should equal(Set("a", "b"))
query.queryGraph.shortestPathPatterns should equal(Set(
ShortestPathPattern(Some("anon_0"), PatternRelationship("r", ("a", "b"), OUTGOING, Seq.empty, SimplePatternLength), single = false)(null)
ShortestPathPattern(Some("anon_0"), PatternRelationship("r", ("a", "b"), OUTGOING, Seq.empty, VarPatternLength(1, Some(1))), single = false)(null)
))
query.tail should be(empty)
}
......@@ -976,7 +976,7 @@ class StatementConvertersTest extends CypherFunSuite with LogicalPlanningTestSup
query.queryGraph.patternNodes should equal(Set("a", "b"))
query.queryGraph.shortestPathPatterns should equal(Set(
ShortestPathPattern(Some("p"), PatternRelationship("r", ("a", "b"), OUTGOING, Seq.empty, SimplePatternLength), single = true)(null)
ShortestPathPattern(Some("p"), PatternRelationship("r", ("a", "b"), OUTGOING, Seq.empty, VarPatternLength(1, Some(1))), single = true)(null)
))
query.tail should be(empty)
}
......
......@@ -28,7 +28,7 @@ class FindShortestPathsPlanningIntegrationTest extends CypherFunSuite with Logic
val cfg = plannerBuilder().setAllNodesCardinality(100).build()
val plan = cfg.plan("MATCH (a), (b), shortestPath((a)-[r]->(b)) RETURN b").stripProduceResults
plan shouldEqual cfg.subPlanBuilder()
.shortestPath("(a)-[r]->(b)", pathName = Some("anon_0"))
.shortestPath("(a)-[r*1..1]->(b)", pathName = Some("anon_0"))
.cartesianProduct()
.|.allNodeScan("b")
.allNodeScan("a")
......@@ -40,7 +40,7 @@ class FindShortestPathsPlanningIntegrationTest extends CypherFunSuite with Logic
val plan = cfg.plan("MATCH (a), (b), p = shortestPath((a)-[r]->(b)) WITH p WHERE length(p) > 1 RETURN p").stripProduceResults
plan shouldEqual cfg.subPlanBuilder()
.filter("length(p) > 1")
.shortestPath("(a)-[r]->(b)", pathName = Some("p"))
.shortestPath("(a)-[r*1..1]->(b)", pathName = Some("p"))
.cartesianProduct()
.|.allNodeScan("b")
.allNodeScan("a")
......@@ -51,7 +51,7 @@ class FindShortestPathsPlanningIntegrationTest extends CypherFunSuite with Logic
val cfg = plannerBuilder().setAllNodesCardinality(100).build()
val plan = cfg.plan("MATCH (a), (b), allShortestPaths((a)-[r]->(b)) RETURN b").stripProduceResults
plan shouldEqual cfg.subPlanBuilder()
.shortestPath("(a)-[r]->(b)", pathName = Some("anon_0"), all = true)
.shortestPath("(a)-[r*1..1]->(b)", pathName = Some("anon_0"), all = true)
.cartesianProduct()
.|.allNodeScan("b")
.allNodeScan("a")
......@@ -68,7 +68,7 @@ class FindShortestPathsPlanningIntegrationTest extends CypherFunSuite with Logic
val plan = cfg.plan("MATCH (a:X)<-[r1]-(b)-[r2]->(c:X), p = shortestPath((a)-[r]->(c)) RETURN p").stripProduceResults
plan shouldEqual cfg.subPlanBuilder()
.shortestPath("(a)-[r]->(c)", pathName = Some("p"))
.shortestPath("(a)-[r*1..1]->(c)", pathName = Some("p"))
.filter("not r1 = r2")
.nodeHashJoin("b")
.|.expandAll("(c)<-[r2]-(b)")
......
......@@ -26,6 +26,7 @@ import org.neo4j.cypher.internal.rewriting.rewriters.factories.PreparatoryRewrit
import org.neo4j.cypher.internal.rewriting.rewriters.insertWithBetweenOptionalMatchAndMatch
import org.neo4j.cypher.internal.rewriting.rewriters.mergeInPredicates
import org.neo4j.cypher.internal.rewriting.rewriters.normalizeWithAndReturnClauses
import org.neo4j.cypher.internal.rewriting.rewriters.rewriteShortestPathWithFixedLengthRelationship
import org.neo4j.cypher.internal.rewriting.rewriters.rewriteShowQuery
import org.neo4j.cypher.internal.util.StepSequencer
import org.neo4j.cypher.internal.util.StepSequencer.AccumulatedSteps
......@@ -42,7 +43,8 @@ case object PreparatoryRewriting extends Phase[BaseContext, BaseState, BaseState
expandCallWhere,
expandShowWhere,
rewriteShowQuery,
mergeInPredicates), initialConditions = Set(LiteralsAreAvailable))
mergeInPredicates,
rewriteShortestPathWithFixedLengthRelationship), initialConditions = Set(LiteralsAreAvailable))
override def process(from: BaseState, context: BaseContext): BaseState = {
......
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.neo4j.cypher.internal.rewriting.rewriters
import org.neo4j.cypher.internal.expressions.NodePattern
import org.neo4j.cypher.internal.expressions.Range
import org.neo4j.cypher.internal.expressions.RelationshipChain
import org.neo4j.cypher.internal.expressions.RelationshipPattern
import org.neo4j.cypher.internal.expressions.ShortestPaths
import org.neo4j.cypher.internal.expressions.UnsignedDecimalIntegerLiteral
import org.neo4j.cypher.internal.rewriting.rewriters.factories.PreparatoryRewritingRewriterFactory
import org.neo4j.cypher.internal.util.CypherExceptionFactory
import org.neo4j.cypher.internal.util.InputPosition
import org.neo4j.cypher.internal.util.InternalNotificationLogger
import org.neo4j.cypher.internal.util.Rewriter
import org.neo4j.cypher.internal.util.StepSequencer
import org.neo4j.cypher.internal.util.StepSequencer.Step
import org.neo4j.cypher.internal.util.topDown
case object NoShortestPathWithFixedLength extends StepSequencer.Condition
/**
* Rewrites shortestPath and allShortestPaths for fixed length relationships to limit 1 or just the pattern.
*/
object rewriteShortestPathWithFixedLengthRel extends Rewriter {
private val instance = topDown(Rewriter.lift {
case s @ ShortestPaths(
r @ RelationshipChain(_: NodePattern, relPat @ RelationshipPattern(_, _, None, _, _, _), _),
_
) =>
val one = Some(UnsignedDecimalIntegerLiteral("1")(InputPosition.NONE))
val range = Some(Some(Range(one, one)(InputPosition.NONE)))
s.copy(element = r.copy(relationship = relPat.copy(length = range)(relPat.position))(r.position))(s.position)
})
override def apply(v: AnyRef): AnyRef = instance(v)
}
case object rewriteShortestPathWithFixedLengthRelationship extends Step with PreparatoryRewritingRewriterFactory {
override def preConditions: Set[StepSequencer.Condition] = Set()
override def postConditions: Set[StepSequencer.Condition] = Set(NoShortestPathWithFixedLength)
override def invalidatedConditions: Set[StepSequencer.Condition] = Set()
override def getRewriter(
cypherExceptionFactory: CypherExceptionFactory,
notificationLogger: InternalNotificationLogger
): Rewriter = rewriteShortestPathWithFixedLengthRel
}
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.neo4j.cypher.internal.rewriting
import org.neo4j.cypher.internal.rewriting.rewriters.rewriteShortestPathWithFixedLengthRel
import org.neo4j.cypher.internal.util.Rewriter
import org.neo4j.cypher.internal.util.test_helpers.CypherFunSuite
class ShortestPathFixedLengthReplacementTest extends CypherFunSuite with RewriteTest {
test("MATCH shortestPath((src)-[r]->(dst)) RETURN *") {
assertRewrite(
"MATCH shortestPath((src)-[r]->(dst)) RETURN *",
"MATCH shortestPath((src)-[r*1..1]->(dst)) RETURN *"
)
}
test("MATCH allShortestPaths((src)-[r]->(dst)) RETURN *") {
assertRewrite(
"MATCH allShortestPaths((src)-[r]->(dst)) RETURN *",
"MATCH allShortestPaths((src)-[r*1..1]->(dst)) RETURN *"
)
}
test("MATCH (src), (dst) WITH allShortestPaths((src)-[r]->(dst)) AS p RETURN *") {
assertRewrite(
"MATCH (src), (dst) WITH allShortestPaths((src)-[r]->(dst)) AS p RETURN *",
"MATCH (src), (dst) WITH allShortestPaths((src)-[r*1..1]->(dst)) AS p RETURN *"
)
}
test("MATCH (src), (dst),p = shortestPath((src)-[r]->(dst)) RETURN src, dst, p") {
assertRewrite(
"MATCH (src), (dst), p = shortestPath((src)-[r]->(dst)) RETURN src, dst, p",
"MATCH (src), (dst), p = shortestPath((src)-[r*1..1]->(dst)) RETURN src, dst, p"
)
}
test("MATCH allShortestPaths((src)-[r*]->(dst)) RETURN *") {
assertIsNotRewritten(
"MATCH allShortestPaths((src)-[r*]->(dst)) RETURN *"
)
}
test("MATCH (src), (dst), p = allShortestPaths((src)-[r*]->(dst)) RETURN *") {
assertIsNotRewritten(
"MATCH (src), (dst), p = allShortestPaths((src)-[r*]->(dst)) RETURN *"
)
}
val rewriterUnderTest: Rewriter = rewriteShortestPathWithFixedLengthRel
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册