RDD源码

RDD 2.4.5

IDEA没有列出主构造函数中的参数,如_sc: SparkContext和deps: Seq[Dependency[_]]

RDD

1
2
3
4
5
// 定义通用操作,其他操作有专门的RDD或操作类实现,如PairRDDFunctions应用于键值对RDD
abstract class RDD[T: ClassTag](
@transient private var _sc: SparkContext,
@transient private var deps: Seq[Dependency[_]]
) extends Serializable with Logging

RDD主要由以下5个属性标识:

  • 分区列表
  • 分区计算函数
  • 对其他RDD的依赖
  • (可选) 键值对RDD分区函数
  • (可选) 用于分区计算的优先存储位置

不允许没有运行作业的嵌套RDD。

不能在转换中嵌套转换或动作,如 rdd1.map(x => rdd2.values.count() * x)

部分方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 分区迭代器
// 用户不应该直接调用,可以被子类继承
final def iterator(split: Partition, context: TaskContext): Iterator[T]

// 深度优先遍历窄依赖,不保证顺序
private[spark] def getNarrowAncestors: Seq[RDD[_]]

// 使用Shuffle再分区,适用于增加分区数。减少分区适用coalesce(numPartitions: Int, false)
def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]

// 再分区
// 不会低于实际的最小分区
// 分区数增大时,使用shuffle。
// 分区数极度减少时,建议使用shuffle, 使上层分区并行计算,避免在极少的节点计算。
// PartitionCoalescer自身没有声明可序列化,实现必须是可序列化的
def coalesce(numPartitions: Int, shuffle: Boolean = false,
partitionCoalescer: Option[PartitionCoalescer] = Option.empty)
(implicit ord: Ordering[T] = null)
: RDD[T]

sc.clean()闭包清理

了解闭包引用的外部变量,并去除不必要的部分(节省带宽),以确保闭包可以序列化。

private[包名],private[this] 可以放在字段,方法和类上,用来限制访问权限;

1private[包名]包名可以是父包名或当前包名,如果是父包名,则父包和子包都可以访问

2private[this]修饰的方法或字段只能在本类访问,如果是字段编译成java的时候就没有get或set方法。

3如果有两个名称相同的子包,比如

package x.y.z.x.v

有两个x,当private[x]的是否离当前包最近的一个包生效

4我的困惑是我查看class文件反编译以后的java类,在class上加private[]的信息去哪了,在反编译的文件中找不到,并且删除scala文件,把生成的class文件放到工程中,他的效果依然存在。

fold():给定一个初始值,累加RDD类元素

aggregate聚合元素并可以返回一个不同于输入类型的返回类型

treeAggregate在语义上与aggregate一致

withScope用于跟踪RDD的操作记录,如Web UI中的DAG图。利用柯里化,withScope中实现跟踪的公共代码,通过body传入业务代码。

要求不能使用return声明。使用最后一行返回机制?

1
private[spark] def withScope[U](body: => U): U = RDDOperationScope.withScope[U](sc)(body)

Spark源码分析(3) RDD 的转换

Spark source understanding withScope

zipWithIndex会触发作业,而zipWithUniqueId不会

take和top用于元素有限的集合,会将全部数据加载到驱动节点

take与takeOrdered相反,前者逆序,后者顺序

++=用于将后者数据追加到前者集合中

RDD确定性:区分RDD重新计算前后的内部状态区别。有以下级别:

  • 确定:相同的输出,相同的顺序
  • 无序:相同的输出,不同的顺序
  • 不确定:不同的顺序

通常取决于父RDD。若父RDD为不确定,则子RDD很可能不确定。

源码 + 文档 + 深入 + 博客

参考资料

RDD internals

[Spark基础]–闭包清理类ClosureCleaner

Scala中类private

spark源码理解之 withScope

Scala入门到精通——第三节 Array、List