zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Spark-SparkSQL深入学习系列二(转自OopsOutOfMemory)

学习Spark 系列 深入 SparkSQL 转自
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)协议,欢迎转载、转发和评论,但是请保留本文作者署名和文章链接。如若需要用于商业目的或者与授权方面的协商,请联系我。

image