一.Spark SQL整体架构
Spark SQL同时支持DataFrame编程API,以及SQL执行和JDBC/ODBC接口,整体结构如下:
Spark SQL是Spark Core之上的一个模块,所有SQL操作最终都通过Catalyst翻译成类似普通Spark程序一样的代码,被Spark Core调度执行,其过程也有Job、Stage、Task的概念。
二.Catalyst执行优化器
Catalyst是Spark SQL执行优化器的代号,所有Spark SQL语句最终都通过它来解析、优化、最终生成可以执行的Java字节码。因此,Catalyst是Spark SQL最核心的部分。而且不同于Shark使用Hive执行优化器的做法,Catalyst是专为Spark设计的,并结合了Scala语言本身的优势,使得性能甚至超过手工编写的Scala代码。
除了性能上的优势之外,Catalyst的扩展性也非常好,它不但可以很方便地添加新的优化技术和新的特性,而且还可以很方便地扩展优化器,比如添加新的数据类型或针对特定数据源的优化规则。
Catalyst最主要的数据结构是树,所有SQL语句都会用树结构来存储,树中的每个节点有一个类,以及0或多个子节点。Scala中定义的新的节点类型都是TreeNode这个类的子类。这些对象都是不可变的。
这里以表达式x+(1+2)为例介绍一下,其中每个元素都对应一个类型。这个表达式总共有3个类型,具体如下:
- Literal(value : Int):一个整数常量类型,1和2都是这个类型。
- Attribute(name : String):表示一个列属性,比如x。
- Add(left : TreeNode, right : TreeNode):表达式类型,用于求和。
所以,表达式最终在Scala中的定义是:Add(Attribute(x),Add(Literal(1),Literal(2)))
这对应一颗树,如下:
Catalyst的另一个重要的概念是规则。基本上所有优化都是基于规则的。可以用规则对树进行操作,树中的节点是只读的,所以树也是只读的。规则中定义的函数可能实现从一棵树转换成一颗新树。
比如,可以定义这样一个规则,将常量相加的子树合并成一个节点:
tree.transform{
case Add(Literal(c1), Literal(c2)) ** => ** Literal(c1 + c2)
}
将这个规则应用到前面的示例x+(