Spark RDD由来原理方法示例源码详解 点击这里免费看全文
文章目录
由来
Spark RDD(Resilient Distributed Datasets)最初由Matei Zaharia等人在UC Berkeley的AMPLab研究组开发,并于2010年首次在Spark项目中引入。
在当时,大数据处理框架主要基于两种模型:分布式文件系统(如HDFS)和批量处理模型(如MapReduce)。然而,这些模型存在一些限制,例如高延迟、磁盘IO开销和无法适应交互式数据处理等问题。
为了解决这些问题,Spark团队设计了RDD作为Spark的核心数据抽象。RDD提供了一种高效、易用且可扩展的数据处理方式,可以在内存中进行计算,从而显著提高了处理速度和性能。
Spark RDD的设计灵感来自于函数式编程和分布式数据库中的概念。它借鉴了函数式编程中的不可变性和惰性计算,以及分布式数据库中的容错性和数据分区。
RDD的核心思想是将数据划分为多个分区,并在每个分区上执行转换操作。这种数据划分和转换的方式使得RDD可以在分布式环境下并行处理数据,并实现容错性和弹性计算。
随着Spark的发展,RDD成为了Spark生态系统的基础,并被广泛应用于各种大数据处理场景。后续版本的Spark进一步完善和优化了RDD的性能、功能和易用性,并引入了其他数据抽象(如DataFrame和Dataset)来满足不同的数据处理需求。
总而言之,Spark RDD是为了解决传统大数据处理框架的限制而设计的一种高性能、可扩展的分布式数据抽象。它的出现推动了大数据处理的革新,使得开发人员能够更方便地进行复杂的数据处理和分析任务。
原理机制
Spark RDD(Resilient Distributed Datasets)是Spark中最基本的数据抽象,它提供了高效、弹性和容错的分布式数据处理能力。以下是Spark RDD的原理机制:
-
分区(Partitions):RDD将数据划分为多个分区,每个分区包含数据的一个子集。分区是作业并行执行的基本单位,每个分区会被分配给集群中的一个任务(Task)进行处理。
-
弹性计算(Resilient Computing):RDD具有容错性,即使在节点故障时也能自动恢复。RDD通过记录转换操作的血统信息来实现容错性。当某个分区数据丢失时,可以根据血统信息重新计算丢失的分区,而无需从头开始执行整个作业。
-
不可变性(Immutability):RDD中的数据是不可变的,一旦创建就不能修改。这意味着对RDD的任何操作都会生成一个新的RDD,而不会直接修改原始数据。这种不可变性有助于确保数据的一致性和线程安全性,并方便了Spark的优化和调度。
-
转换操作(Transformations):RDD支持一系列转换操作,例如map、filter、reduce等,用于对数据进行处理和转换。转换操作会生成一个新的RDD,并记录转换操作的元数据,而不会立即执行计算。
-
行动操作(Actions):RDD提供了一系列行动操作,例如count、collect、reduce等,用于触发实际的计算并获取结果。行动操作会将计算作业提交给Spark集群执行,并返回结果给驱动程序或保存到外部存储中。
-
血统(Lineage):RDD通过记录转换操作的血统信息来实现容错性和弹性计算。血统是一个有向无环图(DAG),描述了RDD之间的依赖关系。当某个分区数据丢失时,可以根据血统信息重新计算丢失的分区。
-
懒执行(Lazy Evaluation):RDD采用惰性计算的方式,即只有在遇到行动操作时才会真正执行计算。在转换操作阶段,RDD仅记录转换操作的元数据而不进行实际计算,这样可以通过优化和调度来减少不必要的计算开销。
-
分区器(Partitioner):对于需要按键进行聚合或排序的RDD,可以使用分区器来控制数据的分区和分布。分区器决定了RDD如何划分为多个分区,并指定了数据在分区之间的分配方式,以便在集群中进行并行处理。
-
数据持久化(Data Persistence):RDD支持将数据持久化到内存或磁盘上,以便在多个计算操作之间重用数据。持久化数据可以提高计算性能,减少重复计算开销。
通过以上原理机制,Spark RDD能够提供高效、弹性和容错的分布式数据处理能力。它将数据划分为多个分区,并在每个分区上执行转换操作,借助血统信息实现容错和弹性计算。同时,RDD支持惰性计算和行动操作,以及数据持久化和分区器等功能,使得开发人员能够方便地进行复杂的数据处理和分析任务。
方法总结
RDD转换操作
++(other: RDD[T]): RDD[T]
: 合并两个RDD中的元素。aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U
: 使用给定的初始值和函数对RDD中的元素进行聚合操作。cartesian[U: ClassTag](other: RDD[U]): RDD[(T, U)]
: 对两个RDD进行笛卡尔积操作。coalesce(numPartitions: Int, shuffle: Boolean = false): RDD[T]
: 将RDD的分区数减少到指定数量。distinct(): RDD[T]
: 去除RDD中的重复元素。filter(f: T => Boolean): RDD[T]
: 根据条件过滤RDD中的元素。flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U]
: 对RDD中的每个元素应用函数并展开结果。groupBy[K](f: T => K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]
: 根据函数对RDD中的元素进行分组。intersection(other: RDD[T]): RDD[T]
: 计算RDD与另一个RDD的交集。map[U: ClassTag](f: T => U): RDD[U]
: 对RDD中的每个元素应用函数。repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]
: 更改RDD的分区数。sample(withReplacement: Boolean, fraction: Double, seed: Long = Utils.random.nextLong): RDD[T]
: 从RDD中随机抽样一部分元素。subtract(other: RDD[T]): RDD[T]
: 从RDD中减去另一个RDD中存在的元素。union(other: RDD[T]): RDD[T]
: 将RDD与另一个RDD进行合并。
RDD行动操作
collect(): Array[T]
: 将RDD中的所有元素收集到数组中。count(): Long
: 统计RDD中的元素数量。first(): T
: 返回RDD中的第一个元素。foreach(f: T => Unit): Unit
: 对RDD中的每个元素应用函数。reduce(f: (T, T) => T): T
: 使用给定的二元函数对RDD中的元素进行归约操作。take(num: Int): Array[T]
: 从RDD中获取指定数量的元素。takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T]
: 获取RDD中排序后的前N个元素。top(num: Int)(implicit ord: Ordering[T]): Array[T]
: 获取RDD中排序后的最大的N个元素。treeAggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U, depth: Int = 2): U
: 在树形结构上对RDD中的元素进行聚合操作。treeReduce(f: (T, T) => T, depth: Int = 2): T
: 在树形结构上对RDD中的元素进行归约操作。
RDD持久化和输出操作
cache(): this.type
: 将RDD缓存到内存中。checkpoint(): Unit
: 对RDD进行检查点操作。persist(): this.type
: 持久化RDD到内存中。persist(newLevel: StorageLevel): this.type
: 持久化RDD到指定的存储级别。unpersist(blocking: Boolean = true): this.type
: 取消对RDD的持久化。saveAsObjectFile(path: String): Unit
: 将RDD以对象文件的格式保存到指定路径。saveAsTextFile(path: String): Unit
: 将RDD以文本文件的格式保存到指定路径。
其他操作
aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U
: 使用给定的初始值和函数对RDD中的元素进行聚合操作。barrier(): RDDBarrier[T]
: 创建一个用于在RDD中插入栅栏的对象。context: SparkContext
: 获取RDD所属的SparkContext对象。countApprox(timeout: Long, confidence: Double = 0.95): PartialResult[BoundedDouble]
: 估计RDD中元素的数量。countApproxDistinct(p: Int, sp: Int): Long
: 估计RDD中不同元素的数量。countByValue()(implicit ord: Ordering[T] = null): Map[T, Long]
: 统计RDD中每个元素出现的次数。distinct(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]
: 去除RDD中的重复元素并重新分区。getCheckpointFile: Option[String]
: 获取RDD的检查点文件路径。getStorageLevel: StorageLevel
: 获取RDD的存储级别。groupBy[K](f: T => K)(p: Partitioner)(implicit kt: ClassTag[K], ord: Ordering[K] = null): RDD[(K, Iterable[T])]
: 根据函数对RDD中的元素进行分组,并使用指定的分区器。isCheckpointed: Boolean
: 判断RDD是否已经被检查点。keyBy[K](f: T => K): RDD[(K, T)]
: 根据函数对RDD中的元素进行键值对转换。localCheckpoint(): this.type
: 对RDD进行本地检查点操作。mapPartitionsWithIndex[U: ClassTag](f: (Int, Iterator[T]) => Iterator[U], preservesPartitioning: Boolean = false): RDD[U]
: 对RDD中的每个分区应用带有分区索引的函数。max()(implicit ord: Ordering[T]): T
: 计算RDD中的最大值。min()(implicit ord: Ordering[T]): T
: 计算RDD中的最小值。pipe(command: String): RDD[String]
: 在RDD中执行外部命令。randomSplit(weights: Array[Double], seed: Long = Utils.random.nextLong): Array[RDD[T]]
: 将RDD按照给定的权重进行随机拆分。sortBy[K](f: T => K, ascending: Boolean = true, numPartitions: Int = this.partitions.length)(implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T]
: 根据指定的键函数对RDD中的元素进行排序。toString: String
: 返回RDD的字符串表示形式。zip[U: ClassTag](other: RDD[U]): RDD[(T, U)]
: 对两个RDD进行元素配对操作。zipPartitions[B: ClassTag, C: ClassTag, D: ClassTag, V: ClassTag](rdd2: RDD[B])(f: (Iterator[T], Iterator[B]) => Iterator[C], preservesPartitioning: Boolean = false)(implicit wt: ClassTag[W], cbf: CanBuildFrom[Seq[V], C, Seq[V]]): RDD[C]
: 对两个RDD的分区进行操作并返回新的RDD。dependencies: Seq[Dependency[_]]
: 获取RDD的依赖关系。getNumPartitions: Int
: 获取RDD的分区数。iterator(split: Partition, context: TaskContext): Iterator[T]
: 获取RDD指定分区的迭代器。partitions: Array[Partition]
: 获取RDD的分区信息。preferredLocations(split: Partition): Seq[String]
: 获取RDD指定分区的首选位置。toDebugString: String
: 获取RDD的调试信息字符串。toJavaRDD(): JavaRDD[T]
: 将RDD转换为JavaRDD。toLocalIterator: Iterator[T]
: 获取RDD的本地迭代器。
示例
以下是对每个函数的代码示例:
RDD转换操作
++(other: RDD[T]): RDD[T]
: 合并两个RDD中的元素。
val rdd1 = sc.parallelize(Seq(1, 2, 3))
val rdd2 = sc.parallelize(Seq(4, 5, 6))
val result = rdd1 ++ rdd2
// result: RDD[Int] = [1, 2, 3, 4, 5, 6]
aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U
: 使用给定的初始值和函数对RDD中的元素进行聚合操作。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.aggregate(0)(_ + _, _ + _)
// result: Int = 15
cartesian[U: ClassTag](other: RDD[U]): RDD[(T, U)]
: 对两个RDD进行笛卡尔积操作。
val rdd1 = sc.parallelize(Seq(1, 2, 3))
val rdd2 = sc.parallelize(Seq("A", "B"))
val result = rdd1.cartesian(rdd2)
// result: RDD[(Int, String)] = [(1, A), (1, B), (2, A), (2, B), (3, A), (3, B)]
coalesce(numPartitions: Int, shuffle: Boolean = false): RDD[T]
: 将RDD的分区数减少到指定数量。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5), 5)
val result = rdd.coalesce(2)
// result: RDD[Int] = [1, 2, 3, 4, 5]
distinct(): RDD[T]
: 去除RDD中的重复元素。
val rdd = sc.parallelize(Seq(1, 2, 2, 3, 3, 3))
val result = rdd.distinct()
// result: RDD[Int] = [1, 2, 3]
filter(f: T => Boolean): RDD[T]
: 根据条件过滤RDD中的元素。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.filter(_ % 2 == 0)
// result: RDD[Int] = [2, 4]
flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U]
: 对RDD中的每个元素应用函数并展开结果。
val rdd = sc.parallelize(Seq("Hello World", "Spark is awesome"))
val result = rdd.flatMap(_.split(" "))
// result: RDD[String] = [Hello, World, Spark, is, awesome]
groupBy[K](f: T => K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]
: 根据函数对RDD中的元素进行分组。
val rdd = sc.parallelize(Seq("apple", "banana", "cherry", "date"))
val result = rdd.groupBy(_.charAt(0))
// result: RDD[(Char, Iterable[String])] = [(a, [apple]), (b, [banana]), (c, [cherry]), (d, [date])]
intersection(other: RDD[T]): RDD[T]
: 计算RDD与另一个RDD的交集。
val rdd1 = sc.parallelize(Seq(1, 2, 3, 4, 5))
val rdd2 = sc.parallelize(Seq(4, 5, 6, 7, 8))
val result = rdd1.intersection(rdd2)
// result: RDD[Int] = [4, 5]
map[U: ClassTag](f: T => U): RDD[U]
: 对RDD中的每个元素应用函数。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.map(_ * 2)
// result: RDD[Int] = [2, 4, 6, 8, 10]
repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]
: 更改RDD的分区数。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.repartition(3)
// result: RDD[Int] = [1, 2, 3, 4, 5]
sample(withReplacement: Boolean, fraction: Double, seed: Long = Utils.random.nextLong): RDD[T]
: 从RDD中随机抽样一部分元素。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.sample(withReplacement = false, fraction = 0.5)
// result: RDD[Int] = [2, 4]
subtract(other: RDD[T]): RDD[T]
: 从RDD中减去另一个RDD中存在的元素。
val rdd1 = sc.parallelize(Seq(1, 2, 3, 4, 5))
val rdd2 = sc.parallelize(Seq(4, 5, 6, 7, 8))
val result = rdd1.subtract(rdd2)
// result: RDD[Int] = [1, 2, 3]
union(other: RDD[T]): RDD[T]
: 将RDD与另一个RDD进行合并。
val rdd1 = sc.parallelize(Seq(1, 2, 3))
val rdd2 = sc.parallelize(Seq(4, 5, 6))
val result = rdd1.union(rdd2)
// result: RDD[Int] = [1, 2, 3, 4, 5, 6]
RDD行动操作
collect(): Array[T]
: 将RDD中的所有元素收集到数组中。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.collect()
// result: Array[Int] = [1, 2, 3, 4, 5]
count(): Long
: 统计RDD中的元素数量。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.count()
// result: Long = 5
first(): T
: 返回RDD中的第一个元素。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.first()
// result: Int = 1
foreach(f: T => Unit): Unit
: 对RDD中的每个元素应用函数。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.foreach(println)
// Output:
// 1
// 2
// 3
// 4
// 5
reduce(f: (T, T) => T): T
: 使用给定的二元函数对RDD中的元素进行归约操作。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.reduce(_ + _)
// result: Int = 15
take(num: Int): Array[T]
: 从RDD中获取指定数量的元素。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.take(3)
// result: Array[Int] = [1, 2, 3]
takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T]
: 获取RDD中排序后的前N个元素。
val rdd = sc.parallelize(Seq(5, 2, 4, 1, 3))
val result = rdd.takeOrdered(3)
// result: Array[Int] = [1, 2, 3]
top(num: Int)(implicit ord: Ordering[T]): Array[T]
: 获取RDD中排序后的最大的N个元素。
val rdd = sc.parallelize(Seq(5, 2, 4, 1, 3))
val result = rdd.top(3)
// result: Array[Int] = [5, 4, 3]
treeAggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U, depth: Int = 2): U
: 在树形结构上对RDD中的元素进行聚合操作。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.treeAggregate(0)(_ + _, _ + _)
// result: Int = 15
treeReduce(f: (T, T) => T, depth: Int = 2): T
: 在树形结构上对RDD中的元素进行归约操作。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.treeReduce(_ + _)
// result: Int = 15
RDD持久化和输出操作
cache(): this.type
: 将RDD缓存到内存中。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.cache()
checkpoint(): Unit
: 对RDD进行检查点操作。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.checkpoint()
persist(): this.type
: 持久化RDD到内存中。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.persist()
persist(newLevel: StorageLevel): this.type
: 持久化RDD到指定的存储级别。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.persist(StorageLevel.DISK_ONLY)
unpersist(blocking: Boolean = true): this.type
: 取消对RDD的持久化。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.unpersist()
saveAsObjectFile(path: String): Unit
: 将RDD以对象文件的格式保存到指定路径。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.saveAsObjectFile("hdfs://path/to/output")
saveAsTextFile(path: String): Unit
: 将RDD以文本文件的格式保存到指定路径。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.saveAsTextFile("hdfs://path/to/output")
其他操作
aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U
: 使用给定的初始值和函数对RDD中的元素进行聚合操作。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.aggregate(0)(_ + _, _ + _)
// result: Int = 15
barrier(): RDDBarrier[T]
: 创建一个用于在RDD中插入栅栏的对象。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val barrier = rdd.barrier()
context: SparkContext
: 获取RDD所属的SparkContext对象。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val context = rdd.context
countApprox(timeout: Long, confidence: Double = 0.95): PartialResult[BoundedDouble]
: 估计RDD中元素的数量。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.countApprox(1000L)
// result: PartialResult[BoundedDouble]
countApproxDistinct(p: Int, sp: Int): Long
: 估计RDD中不同元素的数量。
val rdd = sc.parallelize(Seq(1, 2, 2, 3, 3, 3))
val result = rdd.countApproxDistinct(10, 100)
// result: Long
countByValue()(implicit ord: Ordering[T] = null): Map[T, Long]
: 统计RDD中每个元素出现的次数。
val rdd = sc.parallelize(Seq(1, 2, 2, 3, 3, 3))
val result = rdd.countByValue()
// result: Map[Int, Long] = Map(1 -> 1, 2 -> 2, 3 -> 3)
distinct(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]
: 去除RDD中的重复元素并重新分区。
val rdd = sc.parallelize(Seq(1, 2, 2, 3, 3, 3))
val result = rdd.distinct(2)
// result: RDD[Int] = [1, 2, 3]
getCheckpointFile: Option[String]
: 获取RDD的检查点文件路径。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val checkpointFile = rdd.getCheckpointFile
// checkpointFile: Option[String]
getStorageLevel: StorageLevel
: 获取RDD的存储级别。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val storageLevel = rdd.getStorageLevel
// storageLevel: StorageLevel
groupBy[K](f: T => K)(p: Partitioner)(implicit kt: ClassTag[K], ord: Ordering[K] = null): RDD[(K, Iterable[T])]
: 根据函数对RDD中的元素进行分组,并使用指定的分区器。
val rdd = sc.parallelize(Seq("apple", "banana", "cherry", "date"))
val partitioner = new HashPartitioner(2)
val result = rdd.groupBy(_.charAt(0))(partitioner)
// result: RDD[(Char, Iterable[String])] = [(a, [apple]), (b, [banana, cherry]), (d, [date])]
isCheckpointed: Boolean
: 判断RDD是否已经被检查点。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val isCheckpointed = rdd.isCheckpointed
// isCheckpointed: Boolean
keyBy[K](f: T => K): RDD[(K, T)]
: 根据函数对RDD中的元素进行键值对转换。
val rdd = sc.parallelize(Seq("apple", "banana", "cherry", "date"))
val result = rdd.keyBy(_.charAt(0))
// result: RDD[(Char, String)] = [(a, apple), (b, banana), (c, cherry), (d, date)]
localCheckpoint(): this.type
: 对RDD进行本地检查点操作。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.localCheckpoint()
mapPartitionsWithIndex[U: ClassTag](f: (Int, Iterator[T]) => Iterator[U], preservesPartitioning: Boolean = false): RDD[U]
: 对RDD中的每个分区应用带有分区索引的函数。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5), 3)
val result = rdd.mapPartitionsWithIndex((index, iter) => iter.map(_ + index))
// result: RDD[Int] = [1, 3, 5, 7, 9]
max()(implicit ord: Ordering[T]): T
: 计算RDD中的最大值。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.max()
// result: Int = 5
min()(implicit ord: Ordering[T]): T
: 计算RDD中的最小值。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.min()
// result: Int = 1
pipe(command: String): RDD[String]
: 在RDD中执行外部命令。
val rdd = sc.parallelize(Seq("Hello World", "Spark is awesome"))
val result = rdd.pipe("grep Spark")
// result: RDD[String] = [Spark is awesome]
randomSplit(weights: Array[Double], seed: Long = Utils.random.nextLong): Array[RDD[T]]
: 将RDD按照给定的权重进行随机拆分。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val weights = Array(0.4, 0.6)
val result = rdd.randomSplit(weights)
// result: Array[RDD[Int]] = [[2, 5], [1, 3, 4]]
sortBy[K](f: T => K, ascending: Boolean = true, numPartitions: Int = this.partitions.length)(implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T]
: 根据指定的键函数对RDD中的元素进行排序。
val rdd = sc.parallelize(Seq("apple", "banana", "cherry", "date"))
val result = rdd.sortBy(_.length)
// result: RDD[String] = [date, apple, cherry, banana]
toString: String
: 返回RDD的字符串表示形式。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val str = rdd.toString
// str: String
zip[U: ClassTag](other: RDD[U]): RDD[(T, U)]
: 对两个RDD进行元素配对操作。
val rdd1 = sc.parallelize(Seq(1, 2, 3))
val rdd2 = sc.parallelize(Seq("A", "B", "C"))
val result = rdd1.zip(rdd2)
// result: RDD[(Int, String)] = [(1, A), (2, B), (3, C)]
dependencies: Seq[Dependency[_]]
: 获取RDD的依赖关系。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val dependencies = rdd.dependencies
// dependencies: Seq[Dependency[_]]
getNumPartitions: Int
: 获取RDD的分区数。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val numPartitions = rdd.getNumPartitions
// numPartitions: Int
iterator(split: Partition, context: TaskContext): Iterator[T]
: 获取RDD指定分区的迭代器。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val split = rdd.partitions(0)
val context = TaskContext.get()
val iter = rdd.iterator(split, context)
// iter: Iterator[Int]
partitions: Array[Partition]
: 获取RDD的分区信息。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val partitions = rdd.partitions
// partitions: Array[Partition]
preferredLocations(split: Partition): Seq[String]
: 获取RDD指定分区的首选位置。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val split = rdd.partitions(0)
val locations = rdd.preferredLocations(split)
// locations: Seq[String]
toDebugString: String
: 获取RDD的调试信息字符串。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val debugString = rdd.toDebugString
// debugString: String
toJavaRDD(): JavaRDD[T]
: 将RDD转换为JavaRDD。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val javaRDD = rdd.toJavaRDD()
// javaRDD: JavaRDD[Int]
toLocalIterator: Iterator[T]
: 获取RDD的本地迭代器。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val localIter = rdd.toLocalIterator
// localIter: Iterator[Int]
中文源码
/**
* Resilient Distributed Dataset(RDD)是Spark中的基本抽象概念。它代表一个不可变、分区的元素集合,可以并行操作。
* 这个类包含了所有RDD都可用的基本操作,比如`map`、`filter`和`persist`。另外,[[org.apache.spark.rdd.PairRDDFunctions]]
* 包含了仅适用于键值对RDD的操作,比如`groupByKey`和`join`;
* [[org.apache.spark.rdd.DoubleRDDFunctions]]包含了仅适用于Double类型RDD的操作;而
* [[org.apache.spark.rdd.SequenceFileRDDFunctions]]包含了可以保存为SequenceFiles的RDD的操作。
* 所有这些操作在正确类型的RDD上都会自动可用(例如,RDD[(Int, Int)]),通过隐式转换实现。
*
* 在内部,每个RDD由五个主要属性描述:
*
* - 分区列表
* - 用于计算每个分区的函数
* - 对其他RDD的依赖列表
* - 可选的键值对RDD的Partitioner(例如,指明RDD是哈希分区的)
* - 可选的计算每个分区的首选位置列表(例如,HDFS文件的块位置)
*
* Spark中的调度和执行都是基于这些方法完成的,允许每个RDD实现自己的计算方式。
* 实际上,用户可以通过重写这些函数来实现自定义的RDD(例如,用于从新的存储系统读取数据)。
* 有关RDD内部的更多细节,请参阅<a href="http://people.csail.mit.edu/matei/papers/2012/nsdi_spark.pdf">Spark论文</a>。
*/
abstract class RDD[T: ClassTag](
@transient private var _sc: SparkContext,
@transient private var deps: Seq[Dependency[_]]
) extends Serializable with Logging {
if (classOf[RDD[_]].isAssignableFrom(elementClassTag.runtimeClass)) {
// 这只是一个警告,而不是异常,以避免破坏可能已经定义了嵌套RDD但尚未运行作业的用户程序。
logWarning("Spark不支持嵌套RDD(请参见SPARK-5063)")
}
private def sc: SparkContext = {
if