上一节讲了Spark源码解读之Context的初始化过程,发现其实一行简单的new SparkContext(sparkConf)代码,spark内部会去做很多事情。这节主要讲RDD的构建和转换过程。
一、 RDD概述
RDD (Resilient Distributed Dataset) ,一个弹性分布式数据集,Spark中的基本抽象。代表一个不变(只读)的、可以并行操作的元素的分区集合。Spark中原生的RDD支持从以下三种方式创建:从scala集合中创建、从文件系统中创建、现有RDD的transform操作创建。RDD主要有以下五个特点:
1. 分区集合
RDD是一个分区(partition)的集合,一个RDD有一个或多个分区。分区的数量决定了并行度。使用textFile创建RDD时可以不指定分区数(采用默认的分区数),也可以自己指定分区数。
2. 计算函数以分区为单位
RDD在任务计算时是以分区为单位的,计算函数为compute函数:def compute(split: Partition, context: TaskContext): Iterator[T]。输入参数分别为RDD对应的分区以及task运行环境。不同的RDD子类可以去实现自己的compute方法。
3. RDD依赖于其他RDD
每个RDD都有依赖关系(源RDD的依赖关系为空),这些依赖关系成为lineage,可以通过toDebugString方法来获得lineage。
使用textFile创建的RDD的lineage为HadoopRDD -> MapPartitionsRDD。
4. key-value 类型RDD的 Partitioner
对于非key-value类型的RDD,Partitioner为None,对应key-value类型的RDD,Partitioner默认为HashPartitioner。在进行shuffle操作时,如reduceByKey,sortByKey,Partitioner决定了父RDD shuffle的输出时对应的分区中的数据是如何进行map的。
5. 分区支持数据本地性
Spark在进行任务调度时,会尝试将任务分配到数据所在的机器上,从而避免了机器间的数据传输。RDD获取优先位置的方法为getPreferredLocations。
一般只有涉及到从外部存储结构中读取数据时才会有优先位置,比如HadoopRDD,ShuffledRDD。
二、 实例讲解RDD构建和转换
在idea中对
val WordCounts = sc.textFile("/hosts.txt") .flatMap(text => text.split(" ")) .map(word => (word, 1)) .reduceByKey(_ + _)
进行debug。
1. textFile
SparkContext的textFile方法会从HDFS或本地读取文件,然后创建一个String类型的MapPartitionsRDD。方法如下:
def textFile(
path: String,
minPartitions: Int = defaultMinPartitions): RDD[String] = withScope {
assertNotStopped()
hadoopFile(path, classOf[TextInputFormat], classOf[LongWritable], classOf[Text],
minPartitions).map(pair => pair._2.toString).setName(path)
}
path用于指定文件的路径,minPartitions用于指定最小的分区数,如果不指定minPartition