org.neo4j.cypher.internal.ExecutionEngine
其中execute()
val preParsedQuery = preParser.preParseQuery(query, profile)
val executableQuery = getOrCompile(context, preParsedQuery, queryTracer, params)
if (preParsedQuery.executionMode.name != "explain") {
checkParameters(executableQuery.paramNames, params, executableQuery.extractedParams)
}
val combinedParams = params.updatedWith(executableQuery.extractedParams)
context.executingQuery().compilationCompleted(executableQuery.compilerInfo, supplier(executableQuery.planDescription()))
executableQuery.execute(context, preParsedQuery, combinedParams)
preParsedQuery–>executableQuery
举个例子,查询语句
match (n)-[dad]->(m) where m.age>35 return n.name
翻译成executableQuery
executableQuery.logicalPlan为:
ProduceResult(Vector(n.name)) {
LHS -> Projection(Map(n.name -> Property(Variable(n),PropertyKeyName(name)))) {
LHS -> Expand(m, INCOMING, List(), n, dad, ExpandAll) {
LHS -> Selection(Ands(Set(GreaterThan(Property(Variable(m),PropertyKeyName(age)),Parameter( AUTOINT0,Integer))))) {
LHS -> AllNodesScan(m, Set()) {}
}
}
}
}
其中的Property是org.neo4j.cypher.internal.v3_5.expressions.Property
,定义如下:
case class Property(map: Expression, propertyKey: PropertyKeyName)(val position: InputPosition) extends LogicalProperty {
override def asCanonicalStringVal = s"${map.asCanonicalStringVal}.${propertyKey.asCanonicalStringVal}"
}
PropertyKeyName定义如下:
case class PropertyKeyName(name: String)(val position: InputPosition) extends SymbolicName
executableQuery.executionPlan.resultBuilderFactory.pipe为:
ProduceResultsPipe(ProjectionPipe(ExpandAllPipe(FilterPipe(AllNodesScanPipe(m),m.age > { AUTOINT0}),m,dad,n,INCOMING,org.neo4j.cypher.internal.runtime.interpreted.pipes.LazyTypes@1c395774),InterpretedCommandProjection(Map(n.name -> n.name))),Vector(n.name))
其中的FilterPipe内容如下:
可以看出,其中每个操作被包装为org.neo4j.cypher.internal.runtime.interpreted.pipes.Pipe,每个Pipe子类必须实现如下方法:
def createResults(state: QueryState) : Iterator[ExecutionContext]
如FilterPipe,它的实现如下:
protected def internalCreateResults(input: Iterator[ExecutionContext], state: QueryState): Iterator[ExecutionContext] =
input.filter(ctx => predicate(ctx, state) eq Values.TRUE)
再如AllNodesScanPipe,它的实现如下:
protected def internalCreateResults(state: QueryState): Iterator[ExecutionContext] = {
val baseContext = state.newExecutionContext(executionContextFactory)
state.query.nodeOps.all.map(n => executionContextFactory.copyWith(baseContext, ident, n))
}
org.neo4j.cypher.internal.compatibility.v3_5.runtime.PipeExecutionPlanBuilder.build()负责将logicalPlan翻译成Pipe:
class PipeExecutionPlanBuilder(pipeBuilderFactory: PipeBuilderFactory,
expressionConverters: ExpressionConverters) {
def build(plan: LogicalPlan)
(implicit context: PipeExecutionBuilderContext, tokenContext: TokenContext): Pipe = {
buildPipe(plan)
}
private def buildPipe(plan: LogicalPlan)(implicit context: PipeExecutionBuilderContext, tokenContext: TokenContext): Pipe = {
val pipeBuilder = pipeBuilderFactory(recurse = p => buildPipe(p),
readOnly = context.readOnly,
expressionConverters = expressionConverters)
LogicalPlans.map(plan, pipeBuilder)
}
}
LogicalPlans.map()
的遍历顺序如下:
/**
* Traverses the logical plan tree structure and maps the tree in a bottom but fashion.
*
* Given a logical plan such as:
*
* a
* / \
* b c
* / / \
* d e f
*
* the mapper will be called in the following sequence:
*
* F = mapLeaf(f)
* E = mapLeaf(e)
* C = mapTwoChildPlan(c, E, F)
* D = mapLeaf(d)
* B = mapOneChildPlan(b, D)
* A = mapTwoChildPlan(a, B, C)
*/
org.neo4j.cypher.internal.runtime.interpreted.InterpretedPipeBuilder提供了mapXXX(),负责将logicalPlan节点翻译成Pipe,例如:
def onOneChildPlan(plan: LogicalPlan, source: Pipe): Pipe = {
plan match {
case AllNodesScan(ident, _) =>
AllNodesScanPipe(ident)(id = id)
case Selection(predicate, _) =>
val predicateExpression =
if (predicate.exprs.size == 1) buildExpression(predicate.exprs.head) else buildExpression(predicate)
FilterPipe(source, predicateExpression)(id = id)
...
}
也可以使用explain命令来查看执行计划,需要结合neo4j-browser:
假设具有如下数据:
create (m:man {name: 'bluejoe', age: 40}), (n:man {name: 'alan', age: 39}), (x:kid {name: 'alex', age: 10}), (x)-[:dad]->(m), (m)-[:brother]->(n)
执行如下查询:
explain match (m:man)-[dad]->(x:kid)-[brother]-(n) where m.age<18 and n.age>30 return n.name, m.name, x