spark2原理分析-RDD的Transformations原理分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zg_hover/article/details/83095218

概述

本文介绍RDD的Transformations函数的原理和作用。还会介绍transformations函数的分类,和不同类型的转换产生的效果。

RDD的Transformations操作

transformations简介

在RDD中定义了两类函数:action和transformations。transformations通过在一些RDD中执行一些数据操作来产生一个或更多新的RDD。这些transformations函数包括:map,filter,join,reduceByKey,cogroup,randomSplit等。

也就是说,transformations是这样的一系列函数,它们的输入是一个RDD,输出是一个或多个RDD。但这些函数并不会改变输入RDD的值(这是RDD不可改变的特性),但通过transformations函数的计算会产生一个或多个新的RDD。

transformations的性质

RDD的transformations函数是懒评估(evaluated lazily)的。所谓懒评估是指:在调用transformations函数时不会立即执行,直到action函数被调用。也就是说,transformations函数的执行是由action函数的调用来触发的。

通过使用transformations转换函数,您可以使用最终RDD的所有父RDD逐步构建RDD血缘(RDD Lineage)。

一个RDD通过transformations转换函数处理后得到的新的结果RDD通常与父RDD的值不同,该结果RDD的数据集可能变得更大(例如:flatMap,union等),也可能变得更小(例如:filter,distinct,count等),或则大小相同(例如:map等)。

注意:有些转换函数也可能发起计算,例如:例如sortBy,zipWithIndex等

transformations函数的使用

安装好spark(可以是单机的),并启动spark-shell,在spark-shell中输入一下命令:

1. 加载一个文件,文件内容不重要
scala> val file = sc.textFile("derby.log")
file: org.apache.spark.rdd.RDD[String] = derby.log MapPartitionsRDD[1] at textFile at <console>:24

2. 查看file的结果
scala> file.toDebugString
res14: String =
(2) derby.log MapPartitionsRDD[1] at textFile at <console>:24 []
 |  derby.log HadoopRDD[0] at textFile at <console>:24 []

3. 把文件中的内容按\s+进行分割,也可以执行其他文本操作
scala> val allWords = file.flatMap(_.split("\\s+"))
allWords: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[2] at flatMap at <console>:26

4. 查看一下allWords这个RDD的linage或逻辑执行计划
scala> allWords.toDebugString
res0: String =
(2) MapPartitionsRDD[2] at flatMap at <console>:26 []
 |  derby.log MapPartitionsRDD[1] at textFile at <console>:24 []
 |  derby.log HadoopRDD[0] at textFile at <console>:24 []

从以上第2步的代码和输出可以看到,执行sc.textFile函数后,会产生两种RDD,一种是:HadoopRDD,一种是:MapPartitionsRDD,其中HadoopRDD是中间状态的RDD,最后得到的是MapPartitionsRDD。这个结果从第1步的系统输出可以看到。

然后再对文件中的内容进行处理,会产生新的RDD,产生的新的RDD也是MapPartitionsRDD类型的。从第4步的输出可以看到。

为了更好的理解这些输出,我们可以看一下这些函数的源代码:

  def textFile(
      path: String,
      minPartitions: Int = defaultMinPartitions): RDD[String] = withScope {
    assertNotStopped()
    hadoopFile(path, classOf[TextInputFormat], classOf[LongWritable], classOf[Text],
      minPartitions).map(pair => pair._2.toString).setName(path)
  }

可以看到textFile会调用hadoopFile函数创建一个HadoopRDD,然后再执行map操作,这样就得到了一个MapPartitionsRDD,然后再对该RDD设置一个命令,该RDD的名称被设置为参数path的值。

scala> file.name
res18: String = derby.log

窄转换(Narrow transformations)和宽转换(Wide transformations)

窄转换(Narrow transformations)

窄转换是基于窄依赖(narrow dependencies)进行的RDD转换。

所谓窄依赖是指:父RDD的每个分区最多被儿子RDD的一个分区使用。

因为窄依赖,所以输出的结果RDD的分区数据,都是基于父RDD的单个分区得到的,计算结果是父RDD单个分区数据的子集,所以窄转换不会产生shuffle。

产生窄转换的函数有:map,filter,distinct等。

Spark可以将窄转换进行分组,形成一个pipeline,以便提高计算效率。

宽转换(wide transformations)

宽转换是基于宽依赖(wide dependencies)进行的RDD转换。

所谓宽依赖是指:父RDD的每个分区都可能被子RDD的多个分区使用。

也就是说,计算单个分区中的记录所需的数据可能存在父RDD的多个分区中。所以,宽转换很可能会发生shuffle过程,有时候把宽转换也称为:shuffle transformations。

具有相同key的所有元组必须最终位于同一分区中,由同一任务处理。为了满足这些操作,Spark必须执行RDD shuffle动作,它在集群之间传输数据,使用一组新的分区创建一个新阶段。

导致宽转换的函数有:groupByKey,reduceByKey等。

总结

本文分析了spark RDD的Transformations性质和原理,关于transformations函数的使用可以参考我的这篇文章:通过例子学习spark rdd–Transformations函数

猜你喜欢

转载自blog.csdn.net/zg_hover/article/details/83095218