Spark SQL 语法解析的文件位于 SqlBase.g4 at v2.4.4,其中 JOIN 语句的相关语法定义如下:
1 | fromClause |
From 子句解析这部分的源码位于 AstBuilder.scala at v2.4.4:
1 | /** |
visitFromClause
方法主要处理 fromClause
规则中的多个 relation
规则,根据上面的语法规则及该方法上的注释,我们知道每个 relation
为被 ,
分隔的部分,其中使用了 foldLeft
依次对 relation
处理。在此贴一下 foldLeft
的源码:
1 | def foldLeft[B](z: B)(op: (B, A) => B): B = { |
注意,初始值使用的 null
,然后迭代 relation
进行处理,此时处理的主要为 ,
分隔的 JOIN
表语句,因为 left
的初始值为 null
,所以在 foldLeft
传递的函数中第一行变量的命名为 right
,即第一次迭代时左表为 null
,右表为首次出现的表。然后会根据 left
是否为空执行 optionalMap
方法,源码位于 ParserUtils.scala at v2.4.4:
1 | /** Some syntactic sugar which makes it easier to work with optional clauses for LogicalPlans. */ |
在调用 optionalMap
方法时,plan
为 right
,ctx
为 left
,可知,当首次调用时,不会执行传入的 Join
函数,而是直接返回 plan
即 right
,即首次出现的表对应的逻辑计划。且通过 val join = right.optionalMap(left)(Join(_, _, Inner, None))
可知,在将不同的 relation
进行 JOIN 操作时是采用的 Inner
,且 JOIN 条件为 None
。
以上对于 ctx.relation
的 foldLeft
这一层操作是处理通过 ,
分隔的 relation
语法规则,其中的 withJoinRelations(join, relation)
是对 relation
语法规则内部的 JOIN
语句进行处理,源码位于 AstBuilder.scala at v2.4.4:
1 | /** |
可以看出,与之前的处理逻辑类似,只是这一次是处理的 relation
中的多个 joinRelation
规则,建立单个 relation
下多个 JOIN 语句的关系,其中 Join
类的源码位于 basicLogicalOperators.scala at v2.4.4:
1 | case class Join( |
可知一个 Join
实例由 left
和 right
两个逻辑计划组成,且含有 joinType
和 condition
,即当前 Join
实例的连接类型及条件,以上即为 JOIN 语句的解析流程。最近开发 SQL 解析执行的相关组件,参考了 Spark SQL 的处理逻辑,且因为对 Scala 语法不是很熟,所以简要记录之。