一、RDD概述
RDD是弹性分布式数据集,是spark中数据的抽象。在代码中是一个抽象类,他代表一个抽象类不可变、可分区、元素可并行计算的集合。
- 弹性:存储(内存和磁盘相互切换)、容错(数据丢失可自动恢复)、计算(计算出错重试)、分片(可根据需求重新分片)
- 分布式:数据存储在hdfs上
- 数据集:RDD只保存计算逻辑,不保存数据
- 数据抽象:RDD是一个抽象类,需要具体实现
- 不可变:RDD封装了计算逻辑,是不可变的,想要改变只能生成新的RDD,在新的RDD封装计算逻辑
- 可分区、并行计算
RDD特性:
- 一组分区:getPartitions(对数据进行分区)
- 一个分区函数:compute(封装了分区内数据的计算逻辑)
- RDD之间的依赖:getDependencies(每个RDD之间的转换关系。也称为血缘)
- 一个分区:partitioner(RDD中的分片函数,控制分区的数据流向)
- 一个列表:存储每个partition的优先位置,移动数据不如移动计算,除非资源不足
RDD创建:
- 集合创建:val rdd: RDD[Int] = sc.parallelize(Array(1, 2, 3, 4, 5, 6, 7, 8));val rdd1: RDD[Int] = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7, 8))
- 外部存储创建:val lineWordRdd: RDD[String] = sc.textFile("hdfs://hadoop102:9000/input")
- 其他RDD创建:RDD之间的转换,生成新的RDD
分区规则:
1)、默认分区规则
①、从集合创建:按照机器的核数进行分区,核数和分区数相同
case LOCAL_N_REGEX(threads) =>
def localCpuCount: Int = Runtime.getRuntime.availableProcessors()
val threadCount = if (threads == "*") localCpuCount else threads.toInt
②、从外部存储创建:默认分区数和2取最小值
def defaultMinPartitions: Int = math.min(defaultParallelism, 2)
2)、指定分区规则
①、从集合创建:按照指定发分区数进行分区,按照平均分配原则
//length:数组长度 numSlices:分区数
def positions(length: Long, numSlices: Int): Iterator[(Int, Int)] = {
(0 until numSlices).iterator.map { i =>
val start = ((i * length) / numSlices).toInt
val end = (((i + 1) * length) / numSlices).toInt
(start, end)
}
}
②、从外部存储创建:指定为最小分区数,实际分区数按照切片数确定
private static final double SPLIT_SLOP = 1.1; // 10% slop
ArrayList<FileSplit> splits = new ArrayList<FileSplit>(numSplits);
long bytesRemaining = length;
while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
String[] splitHosts = getSplitHosts(blkLocations,
length-bytesRemaining, splitSize, clusterMap);
splits.add(makeSplit(path, length-bytesRemaining, splitSize,
splitHosts));
bytesRemaining -= splitSize;
}
if (bytesRemaining != 0) {
String[] splitHosts = getSplitHosts(blkLocations, length
- bytesRemaining, bytesRemaining, clusterMap);
splits.add(makeSplit(path, length - bytesRemaining, bytesRemaining,
splitHosts));
}