【spark床头书系列】Spark RDD原理方法示例源码详解

本文深入探讨Spark RDD的由来、原理机制和方法,包括RDD的分区、容错性、不可变性和转换、行动操作。详细讲解了map、collect等操作的源码分析,揭示Spark RDD如何实现高效、弹性和容错的分布式数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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的原理机制:

  1. 分区(Partitions):RDD将数据划分为多个分区,每个分区包含数据的一个子集。分区是作业并行执行的基本单位,每个分区会被分配给集群中的一个任务(Task)进行处理。

  2. 弹性计算(Resilient Computing):RDD具有容错性,即使在节点故障时也能自动恢复。RDD通过记录转换操作的血统信息来实现容错性。当某个分区数据丢失时,可以根据血统信息重新计算丢失的分区,而无需从头开始执行整个作业。

  3. 不可变性(Immutability):RDD中的数据是不可变的,一旦创建就不能修改。这意味着对RDD的任何操作都会生成一个新的RDD,而不会直接修改原始数据。这种不可变性有助于确保数据的一致性和线程安全性,并方便了Spark的优化和调度。

  4. 转换操作(Transformations):RDD支持一系列转换操作,例如map、filter、reduce等,用于对数据进行处理和转换。转换操作会生成一个新的RDD,并记录转换操作的元数据,而不会立即执行计算。

  5. 行动操作(Actions):RDD提供了一系列行动操作,例如count、collect、reduce等,用于触发实际的计算并获取结果。行动操作会将计算作业提交给Spark集群执行,并返回结果给驱动程序或保存到外部存储中。

  6. 血统(Lineage):RDD通过记录转换操作的血统信息来实现容错性和弹性计算。血统是一个有向无环图(DAG),描述了RDD之间的依赖关系。当某个分区数据丢失时,可以根据血统信息重新计算丢失的分区。

  7. 懒执行(Lazy Evaluation):RDD采用惰性计算的方式,即只有在遇到行动操作时才会真正执行计算。在转换操作阶段,RDD仅记录转换操作的元数据而不进行实际计算,这样可以通过优化和调度来减少不必要的计算开销。

  8. 分区器(Partitioner):对于需要按键进行聚合或排序的RDD,可以使用分区器来控制数据的分区和分布。分区器决定了RDD如何划分为多个分区,并指定了数据在分区之间的分配方式,以便在集群中进行并行处理。

  9. 数据持久化(Data Persistence):RDD支持将数据持久化到内存或磁盘上,以便在多个计算操作之间重用数据。持久化数据可以提高计算性能,减少重复计算开销。

通过以上原理机制,Spark RDD能够提供高效、弹性和容错的分布式数据处理能力。它将数据划分为多个分区,并在每个分区上执行转换操作,借助血统信息实现容错和弹性计算。同时,RDD支持惰性计算和行动操作,以及数据持久化和分区器等功能,使得开发人员能够方便地进行复杂的数据处理和分析任务。

方法总结

RDD转换操作

  1. ++(other: RDD[T]): RDD[T]: 合并两个RDD中的元素。
  2. aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U: 使用给定的初始值和函数对RDD中的元素进行聚合操作。
  3. cartesian[U: ClassTag](other: RDD[U]): RDD[(T, U)]: 对两个RDD进行笛卡尔积操作。
  4. coalesce(numPartitions: Int, shuffle: Boolean = false): RDD[T]: 将RDD的分区数减少到指定数量。
  5. distinct(): RDD[T]: 去除RDD中的重复元素。
  6. filter(f: T => Boolean): RDD[T]: 根据条件过滤RDD中的元素。
  7. flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U]: 对RDD中的每个元素应用函数并展开结果。
  8. groupBy[K](f: T => K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]: 根据函数对RDD中的元素进行分组。
  9. intersection(other: RDD[T]): RDD[T]: 计算RDD与另一个RDD的交集。
  10. map[U: ClassTag](f: T => U): RDD[U]: 对RDD中的每个元素应用函数。
  11. repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]: 更改RDD的分区数。
  12. sample(withReplacement: Boolean, fraction: Double, seed: Long = Utils.random.nextLong): RDD[T]: 从RDD中随机抽样一部分元素。
  13. subtract(other: RDD[T]): RDD[T]: 从RDD中减去另一个RDD中存在的元素。
  14. union(other: RDD[T]): RDD[T]: 将RDD与另一个RDD进行合并。

RDD行动操作

  1. collect(): Array[T]: 将RDD中的所有元素收集到数组中。
  2. count(): Long: 统计RDD中的元素数量。
  3. first(): T: 返回RDD中的第一个元素。
  4. foreach(f: T => Unit): Unit: 对RDD中的每个元素应用函数。
  5. reduce(f: (T, T) => T): T: 使用给定的二元函数对RDD中的元素进行归约操作。
  6. take(num: Int): Array[T]: 从RDD中获取指定数量的元素。
  7. takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T]: 获取RDD中排序后的前N个元素。
  8. top(num: Int)(implicit ord: Ordering[T]): Array[T]: 获取RDD中排序后的最大的N个元素。
  9. treeAggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U, depth: Int = 2): U: 在树形结构上对RDD中的元素进行聚合操作。
  10. treeReduce(f: (T, T) => T, depth: Int = 2): T: 在树形结构上对RDD中的元素进行归约操作。

RDD持久化和输出操作

  1. cache(): this.type: 将RDD缓存到内存中。
  2. checkpoint(): Unit: 对RDD进行检查点操作。
  3. persist(): this.type: 持久化RDD到内存中。
  4. persist(newLevel: StorageLevel): this.type: 持久化RDD到指定的存储级别。
  5. unpersist(blocking: Boolean = true): this.type: 取消对RDD的持久化。
  6. saveAsObjectFile(path: String): Unit: 将RDD以对象文件的格式保存到指定路径。
  7. saveAsTextFile(path: String): Unit: 将RDD以文本文件的格式保存到指定路径。

其他操作

  1. aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U: 使用给定的初始值和函数对RDD中的元素进行聚合操作。
  2. barrier(): RDDBarrier[T]: 创建一个用于在RDD中插入栅栏的对象。
  3. context: SparkContext: 获取RDD所属的SparkContext对象。
  4. countApprox(timeout: Long, confidence: Double = 0.95): PartialResult[BoundedDouble]: 估计RDD中元素的数量。
  5. countApproxDistinct(p: Int, sp: Int): Long: 估计RDD中不同元素的数量。
  6. countByValue()(implicit ord: Ordering[T] = null): Map[T, Long]: 统计RDD中每个元素出现的次数。
  7. distinct(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]: 去除RDD中的重复元素并重新分区。
  8. getCheckpointFile: Option[String]: 获取RDD的检查点文件路径。
  9. getStorageLevel: StorageLevel: 获取RDD的存储级别。
  10. groupBy[K](f: T => K)(p: Partitioner)(implicit kt: ClassTag[K], ord: Ordering[K] = null): RDD[(K, Iterable[T])]: 根据函数对RDD中的元素进行分组,并使用指定的分区器。
  11. isCheckpointed: Boolean: 判断RDD是否已经被检查点。
  12. keyBy[K](f: T => K): RDD[(K, T)]: 根据函数对RDD中的元素进行键值对转换。
  13. localCheckpoint(): this.type: 对RDD进行本地检查点操作。
  14. mapPartitionsWithIndex[U: ClassTag](f: (Int, Iterator[T]) => Iterator[U], preservesPartitioning: Boolean = false): RDD[U]: 对RDD中的每个分区应用带有分区索引的函数。
  15. max()(implicit ord: Ordering[T]): T: 计算RDD中的最大值。
  16. min()(implicit ord: Ordering[T]): T: 计算RDD中的最小值。
  17. pipe(command: String): RDD[String]: 在RDD中执行外部命令。
  18. randomSplit(weights: Array[Double], seed: Long = Utils.random.nextLong): Array[RDD[T]]: 将RDD按照给定的权重进行随机拆分。
  19. sortBy[K](f: T => K, ascending: Boolean = true, numPartitions: Int = this.partitions.length)(implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T]: 根据指定的键函数对RDD中的元素进行排序。
  20. toString: String: 返回RDD的字符串表示形式。
  21. zip[U: ClassTag](other: RDD[U]): RDD[(T, U)]: 对两个RDD进行元素配对操作。
  22. 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。
  23. dependencies: Seq[Dependency[_]]: 获取RDD的依赖关系。
  24. getNumPartitions: Int: 获取RDD的分区数。
  25. iterator(split: Partition, context: TaskContext): Iterator[T]: 获取RDD指定分区的迭代器。
  26. partitions: Array[Partition]: 获取RDD的分区信息。
  27. preferredLocations(split: Partition): Seq[String]: 获取RDD指定分区的首选位置。
  28. toDebugString: String: 获取RDD的调试信息字符串。
  29. toJavaRDD(): JavaRDD[T]: 将RDD转换为JavaRDD。
  30. toLocalIterator: Iterator[T]: 获取RDD的本地迭代器。

示例

以下是对每个函数的代码示例:

RDD转换操作

  1. ++(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]
  1. 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
  1. 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)]
  1. 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]
  1. 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]
  1. 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]
  1. 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]
  1. 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])]
  1. 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]
  1. 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]
  1. 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]
  1. 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]
  1. 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]
  1. 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行动操作

  1. 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]
  1. count(): Long: 统计RDD中的元素数量。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.count()
// result: Long = 5
  1. first(): T: 返回RDD中的第一个元素。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.first()
// result: Int = 1
  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
  1. reduce(f: (T, T) => T): T: 使用给定的二元函数对RDD中的元素进行归约操作。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.reduce(_ + _)
// result: Int = 15
  1. 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]
  1. 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]
  1. 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]
  1. 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
  1. 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持久化和输出操作

  1. cache(): this.type: 将RDD缓存到内存中。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.cache()
  1. checkpoint(): Unit: 对RDD进行检查点操作。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.checkpoint()
  1. persist(): this.type: 持久化RDD到内存中。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.persist()
  1. persist(newLevel: StorageLevel): this.type: 持久化RDD到指定的存储级别。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.persist(StorageLevel.DISK_ONLY)
  1. unpersist(blocking: Boolean = true): this.type: 取消对RDD的持久化。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.unpersist()
  1. saveAsObjectFile(path: String): Unit: 将RDD以对象文件的格式保存到指定路径。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.saveAsObjectFile("hdfs://path/to/output")
  1. saveAsTextFile(path: String): Unit: 将RDD以文本文件的格式保存到指定路径。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.saveAsTextFile("hdfs://path/to/output")

其他操作

  1. 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
  1. barrier(): RDDBarrier[T]: 创建一个用于在RDD中插入栅栏的对象。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val barrier = rdd.barrier()
  1. context: SparkContext: 获取RDD所属的SparkContext对象。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val context = rdd.context
  1. 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]
  1. 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
  1. 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)
  1. 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]
  1. getCheckpointFile: Option[String]: 获取RDD的检查点文件路径。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val checkpointFile = rdd.getCheckpointFile
// checkpointFile: Option[String]
  1. getStorageLevel: StorageLevel: 获取RDD的存储级别。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val storageLevel = rdd.getStorageLevel
// storageLevel: StorageLevel
  1. 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])]
  1. isCheckpointed: Boolean: 判断RDD是否已经被检查点。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val isCheckpointed = rdd.isCheckpointed
// isCheckpointed: Boolean
  1. 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)]
  1. localCheckpoint(): this.type: 对RDD进行本地检查点操作。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.localCheckpoint()
  1. 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]
  1. max()(implicit ord: Ordering[T]): T: 计算RDD中的最大值。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.max()
// result: Int = 5
  1. min()(implicit ord: Ordering[T]): T: 计算RDD中的最小值。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val result = rdd.min()
// result: Int = 1
  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]
  1. 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]]
  1. 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]
  1. toString: String: 返回RDD的字符串表示形式。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val str = rdd.toString
// str: String
  1. 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)]
  1. dependencies: Seq[Dependency[_]]: 获取RDD的依赖关系。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val dependencies = rdd.dependencies
// dependencies: Seq[Dependency[_]]
  1. getNumPartitions: Int: 获取RDD的分区数。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val numPartitions = rdd.getNumPartitions
// numPartitions: Int
  1. 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]
  1. partitions: Array[Partition]: 获取RDD的分区信息。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val partitions = rdd.partitions
// partitions: Array[Partition]
  1. 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]
  1. toDebugString: String: 获取RDD的调试信息字符串。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val debugString = rdd.toDebugString
// debugString: String
  1. toJavaRDD(): JavaRDD[T]: 将RDD转换为JavaRDD。
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
val javaRDD = rdd.toJavaRDD()
// javaRDD: JavaRDD[Int]
  1. 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 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值