RDD看起来好像很抽象,但我的理解就是类似于我们自己写一个java程序,会编写一个数据模型的类来组织我们的数据一样,RDD其实就是Spark中的数据模型,也就是Spark自己编写的类,RDD有三个必不可少的部分:(1)RDD对其他RDD的依赖,即血系图;(2)分区列表;(3)针对分区的计算函数;
(1)RDD对其他RDD的依赖
1.1 RDD中persist和unpersist方法实质上就是往SparkContext类中定义的TimeStampedWeakValueHashMap[Int, RDD[_]]变量中添加或者删除RDD记录(包括RDD的id,RDD本身);
1.2 Dependency
Dependency体现出RDD的依赖关系,通过它可以获得血系图,Dependency中一个最重要的方法就是getParent()
def getParents(partitionId: Int): Seq[Int]//输入子RDD的一个分区id,返回子RDD的该分区所依赖的父RDD的分区id所组成的序列
为什么getParents没有方法的实现呢?
我是这样理解的:如一对一依赖,子RDD和父RDD是一对一的,而且子RDD沿用父RDD的分区id,那子RDD调用该方法是实质返回的也就是自己的分区id,因此直接可以用Seq[Int]了,至于宽依赖好像就不好理解了,不过思路就是宽依赖中子RDD要依赖父RDD的所有分区
(2)分区列表
2.1 Partitioner
划分器,宽依赖即shuffle操作时用到,用来对shuffle的输出结果进行分区(包括分区id,分区的位置等),窄依赖或者说一对一依赖时不需要,因为子RDD会沿用父RDD的分区信息(包括分区的位置,分区id等),默认的分区器为HashPartitioner哈希划分器,分区数目一般默认为“spark.default.parallelism”指定的值(通常为2)
<script src="https://code.youkuaiyun.com/snippets/624739.js"></script>
此外划分器还有RangePartitioner范围划分器,当然我觉得自己也可以实现自己的划分器,只需要在Partitioner类中实现一个自定义的划分器类,然后在Partitioner类中的defaultPartitioner方法中将new HashPartitioner改为自己定义的类就好了,不过这需要对spark重新进行编译,划分器的效率关系的shuffle操作的性能
2.2. Partition
Partition类即分区类,该类中重写了hashCode()方法,返回的是分区索引;
RDD中调用partitions()方法返回RDD中各个分区索引数组,即Array[Partition]
未完待续。。。