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 语法不是很熟,所以简要记录之。