版权声明:本文为博主原创文章,未经博主允许不得转载。
手动码字不易,请大家尊重劳动成果,谢谢
作者:http://blog.csdn.net/wang_wbq
Spark SQL之所以能支持如此强大的表达式系统,是因为其包含了一套字符串解析并生成表达式树的模块。
在Spark 2.0之前,Spark SQL使用Scala Parser功能去解析SQL表达式,其解析类为org.apache.spark.sql.catalyst.SqlParser
。
对于没用使用过Scala Parser的人来讲,这个类基本上就可以称为天书了。其中用到的几个基本符号:
~ 连接符,并将左右侧匹配结果保留
~> 连接符,仅保留右侧匹配结果,左侧将丢弃
<~ 连接符,仅保留左侧匹配结果,右侧将丢弃。该连接符优先级低于 ~ 和 ~>
^^ 其左侧为词法表达式,右侧为一个函数
例如:p1 ~ p2 ^^ { case a ~ b => a + b }
这个表达式可以把p1和p2匹配出的结果分别赋值给a和b,
注意:此处的前后两个 ~ 不是同一个函数; ^^ 左右匹配结果的数量必须一致
? 和正则表达式中一样,表示可有可无
* 和正则表达式中一样,表示可以有零个或多个
*(sep: => Parser[(U, U) => U]) 表示this (sep this)*
例如:andExpression * (OR ^^^ { (e1: Expression, e2: Expression) => Or(e1, e2) })
上面表达式的意思就是:
andExpression (OR andExpression)*
将*展开就是:
andExpression OR andExpression OR andExpression ...
一个andExpression后面跟上一堆可重复的 OR andExpression
+ 和正则表达式中一样,表示可以至少有一个
^^^ 如果其左侧匹配成功,则丢弃左边,返回右侧运算结果
Scala Parser原理简介
https://blog.csdn.net/wang_wbq/article/details/79794897
在Spark 2.0之后,Spark SQL使用Antlr 4来解析SQL表达式,其解析描述文件路径为spark源码根路径\sql\catalyst\src\main\antlr4\org\apache\spark\sql\catalyst\parser\SqlBase.g4
。
但是只有描述文件是不能解析表达式的,需要先将其变换成代码。
在spark-catalyst的pom文件里,我们可以看到它引入了antlr4的maven插件:
<plugin>
<groupId>org.antlrgroupId>
<artifactId>antlr4-maven-pluginartifactId>
<executions>
<execution>
<goals>
<goal>antlr4goal>
goals>
execution>
executions>
<configuration>
<visitor>truevisitor>
<sourceDirectory>../catalyst/src/main/antlr4sourceDirectory>
configuration>
plugin>
其中
会在
生命周期内执行描述文件的解析,并且在target\generated-sources\antlr4
下生成表达式解析的java文件:
Antlr 4是一个非常优秀的词法语法分析工具,借助它你可以实现很多自定义表达式解析,甚至可以做一个简单的编译器。Antlr 4使用了Visitor模式和Listener模式来帮助使用者对解析好的表达式进行处理。
Visitor模式即Antlr 4已经将表达式按照你给的规则解析成为一个语法树。然后把语法树的根节点交给你,你去决定该往哪走。
Listener模式即Antlr 4已经将表达式按照你给的规则解析成为一个语法树。然后自己执行深度优先遍历,然后在遍历到每个节点的时候给你发送事件。
我之前学习Antlr 4的时候写过一个表达式解析器,可以通过这个链接来查看。这个程序可以解析一个自定义模式的表达式,然后生成Spark SQL可用的表达式。具体实例可以参考代码中的测试用例部分。
如果你使用Spark 2.0之后的版本,你可以下载Antlr 4的IDEA插件来测试SqlBase.g4
文件,其中singleStatement
为整个SQL语句的解析器,singleExpression
为单个表达式的解析器,我在平常工作中测试singleExpression
居多,在写代码前先用插件测试下这个表达式的合法性,然后再写到代码里运行,这样可以大大增加代码的运行成功率。
以下是我使用singleExpression
对表达式进行解析的结果,右侧为Antlr 4插件生成的表达式树: