第16课:RDD实战
本期内容:
1. RDD实战
2. RDD的Transformation与Action
3. RDD执行手动绘图
RDD的操作:
1 Transformation:数据状态转换,即算子,是基于已有的RDD创建一个新的RDD
2 Action:触发作业。是最后取结果的操作。因为RDD是Lazy级别的,性能非常高,从后往前回溯。如foreach/reduce/saveAsTextFile,这些都可以保存结果到HDFS或给Driver。
3 Controller:性能、效率、容错的支持。即cache/persist/checkpoint
RDD.scala类中的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, (context, pid, iter) => iter.map(cleanF))
}
可以看出map函数收受一个参数,这个参数本身是个函数f,传入类型为T,返回类型为U。map函数内部会产生一个MapParititionsRDD,对已有的map作用的RDD的每个元素自定义一个函数f来处理每一个元素,元素的类型就是T,返回的类型就是U,基于U类型的元素构成集合产生新的RDD。
RDD.scala类中的reduce函数的源码如下:
/**
* Reduces the elements of this RDD using the specified commutative and
* associative binary operator.
*/
def reduce(f: (T, T) => T): T = withScope {
val cleanF = sc.clean(f)
val reducePartition: Iterator[T] => Option[T] = iter => {
if (iter.hasNext) {
Some(iter.reduceLeft(cleanF))
} else {
None
}
}
var jobResult: Option[T] = None
val mergeResult = (index: Int, taskResult: Option[T]) => {
if (taskResult.isDefined) {
jobResult = jobResult match {
case Some(value) => Some(f(value, taskResult.get))
case None => taskResult
}
}
}
sc.runJob(this, reducePartition, mergeResult)
// Get the final result out of our Option, or throw an exception if the RDD was empty
jobResult.getOrElse(throw new UnsupportedOperationException("empty collection"))
}
reduce函数是对RDD中的所有元素进行聚合操作,得出最终结果返回给Driver。要符合结合律(commutative )和交换律(associative)。原因是reduce操作时并不知道哪个数据先到,所以必须满足交换律,另一方面,只有满足结合律才能进行reduce。
Transformation的特点就是Lazy,Lazy就是Spark应用程序中使用Transformation操作只是标记这个操作,而不会真正执行。只有在遇到Action或Checkpoint时才会真正执行操作,通过Lazy特性就可以对Spark应用程序进行优化。原因是一直延迟执行,Spark就可以看到很多步骤,看到的步骤越多,优化的空间越大。最简单的就是把所有的步骤合并。
Action会触发JOB。sc.runJob方法导致作业运行。
下面以统计文件中相同行的个数为例