Spark 总结之RDD(二)
1. 背景
- Spark作为分布式数据处理引擎,在企业实践中大量应用.对比Mapreduce既有性能上的优势,也有开发编程上的便捷性优势.
- Spark针对数据处理,对编程接口做了更高层级的抽象和封装,API使用起来更加方便.其中RDD DataSet DataFrame DStream等都是抽象出来的数据处理对象.
- RDD使用时会屏蔽掉具体细节,操作起来就跟操作Scala的集合对象一样便捷.
2. RDD常见算子和方法
2.1 RDD创建 查看方法
- RDD创建
package com.doit.rddInfo
import org.apache.spark.rdd.RDD
import org.apache.spark.{
SparkConf, SparkContext}
class RDDInfo1{
}
object RDDInfo1 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
conf.setAppName(classOf[RDDInfo1].toString )
conf.setMaster("spark://linux101:7077")
val sc = new SparkContext(conf)
val array: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8)
// 创建rdd
val rdd1: RDD[Int] = sc.parallelize(array)
val rdd2: RDD[Int] = sc.makeRDD(array)
// 指定数据分区,分区数决定了并行task数
val rdd3: RDD[Int] = sc.parallelize(array, 4)
val rdd4: RDD[Int] = sc.makeRDD(array, 6)
println(rdd1.collect().toBuffer)
println("======")
println(rdd2.collect().toBuffer)
println("======")
println(rdd3.collect().toBuffer)
println("======")
println(rdd4.collect().toBuffer)
println("======")
sc.stop()
}
}
- 查看分区数量
rdd1.partitions.length
2.2 RDD常见Transformation算子
1. map算子
- 最核心最关键的算子之一,顾名思义,主要是做转换数据使用,由此可以延伸出多种用途.
val conf = new SparkConf()
conf.setAppName(classOf[RDDInfo1].toString )
conf.setMaster("spark://linux101:7077")
val sc = new SparkContext(conf)
val array: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8)
// 创建rdd
val rdd1: RDD[Int] = sc.parallelize(array)
// 数据转换
val mapedValue: RDD[Int] = rdd1.map(ele => ele * 10)
- map方法的源码
/**
* Return a new RDD by applying a function to all elements of this RDD.
*/
def map[U: ClassTag](f: T => U): RDD[U] = withScope {
val cleanF = sc.clean(f)
new MapPartitionsRDD[U, T](this, (_, _, iter) => iter.map(cleanF))
}
private[spark] def clean[F <: AnyRef](f: F, checkSerializable: Boolean = true): F = {
ClosureCleaner.clean(f, checkSerializable)
f
}
上面可以看出,
map方法参数就是一个函数, 泛型T=>U
map方法返回是一个RDD
map方法内部实现是,先调用sc.clean(f),这是因为RDD内部包含的是数据来源和数据处理逻辑,最终是要转换为Task对象序列化之后分发给各个executor执行的,所以需要检查是否包含不可序列化的内容
接下来就是创建了一个MapPartitionsRDD对象,这个对象接收2个参数,一个是this,就是当前的RDD,一个是函数
(_, _, iter) => iter.map(cleanF),从函数构成来看,大致最后一个参数是一个迭代器,通过迭代器,让每个迭代器中元素应用一次传进来的函数
private[spark] class MapPartitionsRDD[U: ClassTag, T: ClassTag](
var prev: RDD[T],
f: (TaskContext, Int, Iterator[T]) => Iterator[U], // (TaskContext, partition index, iterator)
preservesPartitioning: Boolean = false,
isFromBarrier: Boolean = false,
isOrderSensitive: Boolean = false)
extends RDD[U](prev)