Spark-SparkSQL深入学习系列二(转自OopsOutOfMemory)
2023-09-27 14:26:36 时间
1. 当我们调用sql("select name,value from temp_shengli")时,实际上是new了一个SchemaRDD
2. new SchemaRDD时,构造方法调用parseSql方法,parseSql方法实例化了一个SqlParser,这个Parser初始化调用其apply方法。 3. apply方法分支: 3.1 如果sql命令是set开头的就调用SetCommand,这个类似Hive里的参数设定,SetCommand其实是一个Catalyst里TreeNode之LeafNode,也是继承自LogicalPlan,关于Catalyst的TreeNode库这个暂不详细介绍,后面会有文章来详细讲解。 3.2 关键是else语句块里,才是SqlParser解析SQL的核心代码:可能 phrase方法大家很陌生,不知道是干什么的,那么我们首先看一下SqlParser的类图:
SqlParser类继承了scala内置集合Parsers,这个Parsers。我们可以看到SqlParser现在是具有了分词的功能,也能解析combiner的语句(类似p ~ q,后面会介绍)。 Phrase方法:
lastNoSuccessVar.value filterNot { _.next.pos in1.pos } getOrElse Failure("end of input expected", in1)
Phrase是一个循环读取输入字符的方法,如果输入in没有到达最后一个字符,就继续对parser进行解析,直到最后一个输入字符。 我们注意到Success这个类,出现在Parser里, 在else块里最终返回的也有Success:
case class Success[+T](result: T, override val next: Input) extends ParseResult[T] {
所以上面判断了Success的解析结果中in1.atEnd? 如果输入流结束了,就返回s,即Success对象,这个Success包含了SqlParser解析的输出。
二、Sql Parser核心 在SqlParser里phrase接受2个参数: 第一个是query,一种带模式的解析规则,返回的是LogicalPlan。 第二个是lexical词汇扫描输入。 SqlParser parse的流程是,用lexical词汇扫描接受SQL关键字,使用query模式来解析符合规则的SQL。
2.1 lexical keyword 在SqlParser里定义了KeyWord这个类:
2.2 query query的定义是Parser[LogicalPlan] 和 一堆奇怪的连接符(其实都是Parser的方法啦,看上图),*,~,^^^,看起来很让人费解。通过查阅读源码,以下列出几个常用的: | is the alternation combinator. It says “succeed if either the left or right operand parse successfully”
左边算子和右边的算子只要有一个成功了,就返回succeed,类似or
~ is the sequential combinator. It says “succeed if the left operand parses successfully, and then the right parses successfully on the remaining input”
左边的算子成功后,右边的算子对后续的输入也计算成功,就返回succeed
opt `opt(p)` is a parser that returns `Some(x)` if `p` returns `x` and `None` if `p` fails.
如果p算子成功则返回则返回Some(x) 如果p算子失败,返回fails
^^^ `p ^^^ v` succeeds if `p` succeeds; discards its result, and returns `v` instead.
如果左边的算子成功,取消左边算子的结果,返回右边算子。
~ says “succeed if the left operand parses successfully followed by the right, but do not include the left content in the result”
如果左边的算子和右边的算子都成功了,返回的结果中不包含左边的返回值。
protected lazy val limit: Parser[Expression] =
LIMIT ~ expression
~ is the reverse, “succeed if the left operand is parsed successfully followed by the right, but do not include the right content in the result”
这个和~ 操作符的意思相反,如果左边的算子和右边的算子都成功了,返回的结果中不包含右边的
termExpression ~ IS ~ NOT ~ NULL ^^ { case e = IsNotNull(e) } |
^^{} 或者 ^^= is the transformation combinator. It says “if the left operand parses successfully, transform the result using the function on the right”
rep = simply says “expect N-many repetitions of parser X” where X is the parser passed as an argument to rep
变形连接符,意思是如果左边的算子成功了,用^^右边的算子函数作用于返回的结果 接下来看query的定义:
UNION ~ opt(DISTINCT) ^^^ { (q1: LogicalPlan, q2: LogicalPlan) = Distinct(Union(q1, q2)) }
没错,返回的是一个Parser,里面的类型是LogicalPlan。 query的定义其实是一种模式,用到了上述的诸多操作符,如|, ^^, ~ 等等 给定一种sql模式,如select,select xxx from yyy where ccc =ddd 如果匹配这种写法,则返回Success,否则返回Failure. 这里的模式是select 模式后面可以接union all 或者 union distinct。 即如下书写式合法的,否则出错。
val withDistinct = d.map(_ = Distinct(withProjection)).getOrElse(withProjection)
看这个select语句支持什么模式的写法: select distinct projections from filter grouping having orderBy limit. 给出一个符合的该select 模式的sql, 注意到 带opt连接符的是可选的,可以写distinct也可以不写。
select game_id, user_name from game_log where date =2014-07-19 and user_name=shengli group by game_id having game_id 1 orderBy game_id limit 50.
projections是什么呢? 其实是一个表达式,是一个Seq类型,一连串的表达式可以使 game_id也可以是 game_id AS gmid 。 返回的确实是一个Expression,是Catalyst里TreeNode。
三、总结 本文从源代码剖析了Spark Catalyst 是如何将Sql解析成Unresolved逻辑计划(包含UnresolvedRelation、 UnresolvedFunction、 UnresolvedAttribute)的。 sql文本作为输入,实例化了SqlParser,SqlParser的apply方法被调用,分别处理2种输入,一种是命令参数,一种是sql。对应命令参数的会生成一个叶子节点,SetCommand,对于sql语句,会调用Parser的phrase方法,由lexical的Scanner来扫描输入,分词,最后由query这个由我们定义好的sql模式利用parser的连接符来验证是否符合sql标准,如果符合则随即生成LogicalPlan语法树,不符合则会提示解析失败。 通过对spark catalyst sql parser的解析,使我理解了,sql语言的语法标准是如何实现的和如何解析sql生成逻辑计划语法树。 ——EOF——
原创文章,转载请注明: 转载自:OopsOutOfMemory盛利的Blog,作者: OopsOutOfMemory 本文链接地址:http://blog.csdn.net/oopsoom/article/details/37943507 注:本文基于署名-非商业性使用-禁止演绎 2.5 中国大陆(CC BY-NC-ND 2.5 CN)协议,欢迎转载、转发和评论,但是请保留本文作者署名和文章链接。如若需要用于商业目的或者与授权方面的协商,请联系我。
相关文章
- 云风的Blog 学习神经网络的一点笔记
- 对于SQL的Join,在学习起来可能是比较乱的。我们知道,SQL的Join语法有很多inner的,有outer的,有left的,有时候,对于Select出来的结果集是什么样子有点不是很清楚。Coding Horror上有一篇文章,通过文氏图 Venn diagrams 解释了SQL的Join。我觉得清楚易懂,转过来。 交差集" cross join 《Linux命令行与shell脚本编程大全
- Spark学习笔记
- C#学习记录——流程控制:布尔逻辑、布尔按位运算符和赋值运算符、运算符优先级的更新、分支
- Spark学习笔记01-基础
- 【XCP学习】在测量和校准应用的焦点:XCP-4
- Apache Spark机器学习.1.9 小结
- Apache Spark机器学习3.5 模型评估
- Caffe学习系列(11):图像数据转换成db(leveldb/lmdb)文件
- Redis学习手册(Key操作命令)
- 大数据学习——spark笔记
- 大数据学习——spark安装
- 《Spark与Hadoop大数据分析》一一3.2 学习Spark的核心概念
- 《Scala机器学习》一一第3章 使用Spark和MLlib
- 学习笔记(41):Python实战编程-按钮
- Arduino学习笔记70