Spark Catalyst 源码解析:Parser
在
上一篇文章
中,我们了解了 SparkSQL 查询的基本执行过程,并了解到
SQLContext
的内部类
QueryExecution
包含了整个执行过程的每一个执行步骤。
在这篇文章中,我将开始讲解 SQL 语句如何通过 Parser 转变为 Unresolved Logical Plan。
DDLParser
1 |
|
可以看到,
parseSql
方法调用了
ddlParser
的
parse
方法。
ddlParser
在初始化时传入了
sqlParser.parse
方法作为参数,而
sqlParser
在初始化时也传入了一个 SQL 方言的
parse
方法作为参数。这三个
parse
之间很有可能是一个
fallback
的关系。那我们先来看看
DDLParser
:
1 |
/** |
先不急着往下看,因为这里调用了
AbstractSparkSQLParser
的
parse
方法。我们先看看
AbstractSparkSQLParser
:
1 |
private[sql] abstract class AbstractSparkSQLParser |
我们看到,真正启动
parse
过程的实际上是如下代码块:
1 |
phrase(start)(new lexical.Scanner(input)) match { |
这里调用的
phrase
方法实际上来自于
AbstractSparkSQLParser
的父类
PackratParsers
。
PackratParsers
和
StandardTokenParsers
实际上都是 Scala 自带的类。它们的功能较为复杂,而且 SparkSQL 本身的作用原理关系并不是很大,我在这里就简单讲述一下。
1 |
// PackratParsers.scala |
可以看到,
PackratParsers#phrase
方法接受一个
Parser
作为参数,并以其为参数调用了其父类
Parsers
的
phrase
方法,该方法同样返回一个
Parser
。而后,
PackratParsers#phrase
返回了一个
PackratParser
,由
AbstractSparkSQLParser
调用这个对象的
apply
方法传入 SQL 语句。
我们回到
DDLParser
:
1 |
private[sql] class DDLParser(parseQuery: String => LogicalPlan) |
在接下来的代码中,
AbstractSparkSQLParser
实现了三个 parser:
createTable
、
describeTable
和
refreshTable
,并将其重载为
AbstractSparkSQLParser#start
变量,由此
DDLParser
改变了
AbstractSparkSQLParser#start
的功能。
上述的这些 Keyword 全都是 Spark 所支持的 DLL keyword,没有包含 SQL 的保留字。不难想象
DDLParser
仅用于解析 DDL 语句,当遇到 SQL 语句时,解析器将 fallback 到实例化
DDLTask
时传入的
parseQuery
函数,而这个函数正是
SparkSQLParser#parse
函数。