本文主要简述InternalRow、TreeNode及其子类。
一、InternalRow
在Spark SQL的内部实现中,InternalRow就是用来表示一行行数据的,也就是说在物理计划执行的阶段,Spark SQL转换和操作的都是RDD[InternalRow]。
其UML类图如下:
其中:
- UnsafeRow:不采用java对象存储的方式,避免了JVM GC的代价。
- JoinRow: 用于join操作,将俩个InternalRow连接形成新的InternalRow
- ColumnarRow: 主要用于ColumnVector中getStruct时返回列原始信息;The data for this row E.g. the value of 3rd int field is `data.getChild(3).getInt(rowId)`.
- MutableColumnarRow:是ColumnarRow的可变版本,主要是用于hash map的聚合计算。
- MutableUnsafeRow:UnsafeRow的辅助类,用于更新UnsafeRow中的字段值,主要使用地方在ColumnAccessor
二、TreeNode
TreeNode在逻辑计划和物理计划阶段都扮演着重要的角色TreeNode是scala.Product类型,同时它一直在内存中维护,在analyzed和optimized的阶段都是以替换现有的节点的方式来实现。
TreeNode有俩个主要的子类,一个是Expression,代表表达式,另外一个是QueryPlan代表查询计划,它有俩个主要的子类就是逻辑查询计划(LogicPlan)、物理查询计划(Spark Plan)。
TreeNode定义的主要的基本操作有:
- collectLeaves 获取当前节点的所有叶子节点
- collectFirst 先序遍历所有节点并返回第一个满足条件的节点
- withNewChildren 将当前子节点替换成新的节点
- transformDown 先序遍历应用规则到各个节点
- transfUp 后序遍历应用规则到各个节点
- transformChildren 递归方式遍历应用规则到各个节点
Expression简述:
- foldable: 标记是否可以改表达式是否可以直接计算,1、字面量2、所有的子节点改标记都为true
- deterministic: 该表达式是否为确定性,即每次执行eval函数输出一致
- eval 返回给定的输入的结果
- doGenCode:生成eval的java可执行的源代码
- genCode: 调用doGencode执行返回包装了eval java执行源代码的ExprCode
本文主要介绍了InternalRow和TreeNode大体的结构,internalRow主要用于计划执行期间的数据转换和表达,TreeNode主要是在计划执行之前对整个计划树进行操作时的中间数据。
参考:《spark sql 内存剖析》