RDD的依赖关系

Rdd之间的依赖关系通过rdd中的getDependencies来进行表示,

在提交job后,会通过在DAGShuduler.submitStage-->getMissingParentStages

privatedefgetMissingParentStages(stage:
Stage): List[Stage] = {

valmissing
=newHashSet[Stage]

valvisited
=newHashSet[RDD[_]]

defvisit(rdd: RDD[_]) {

if(!visited(rdd)){

visited+= rdd

if(getCacheLocs(rdd).contains(Nil)){

for(dep
<-rdd.dependencies) {

depmatch{

caseshufDep:ShuffleDependency[_,_]
=>

valmapStage
=getShuffleMapStage(shufDep,stage.jobId)

if(!mapStage.isAvailable){

missing+=
mapStage

}

casenarrowDep:NarrowDependency[_]
=>

visit(narrowDep.rdd)

}

}

}

}

}

visit(stage.rdd)

missing.toList

}

在以上代码中得到rdd的相关dependencies,每个rdd生成时传入rdd的dependencies信息。

如SparkContext.textFile,时生成的HadoopRDD时。此RDD的默觉得dependencys为Nil.

Nil是一个空的列表。

classHadoopRDD[K, V](

sc: SparkContext,

broadcastedConf:Broadcast[SerializableWritable[Configuration]],

initLocalJobConfFuncOpt:Option[JobConf => Unit],

inputFormatClass: Class[_ <:InputFormat[K, V]],

keyClass: Class[K],

valueClass: Class[V],

minSplits: Int)

extendsRDD[(K,
V)](sc, Nil) withLogging {

Dependency分为ShuffleDependency与NarrowDependency。

当中NarrowDependency又包括OneToOneDependency/RangeDependency

Dependency唯一的成员就是rdd,即所依赖的rdd,或parentrdd

abstractclassDependency[T](valrdd:RDD[T])
extendsSerializable

OneToOneDependency关系:

最简单的依赖关系,即parent和child里面的partitions是一一相应的,典型的操作就是map,filter

事实上partitionId就是partition在RDD中的序号,所以假设是一一相应,

那么parent和child中的partition的序号应该是一样的,例如以下是OneToOneDependency的定义

/**

*Represents a one-to-one dependency between partitions of the parentand child RDDs.

*/

classOneToOneDependency[T](rdd: RDD[T])
extendsNarrowDependency[T](rdd) {

此类的Dependency中parent中的partitionId与childRDD中的partitionId是一对一的关系。

也就是partition本身范围不会改变,一个parition经过transform还是一个partition,

尽管内容发生了变化,所以能够在local完毕,此类场景通常像mapreduce中仅仅有map的场景,

第一个RDD运行完毕后的MAP的parition直接运行第二个RDD的Map,也就是local运行。

overridedefgetParents(partitionId:
Int) = List(partitionId)

}

RangeDependency关系:

此类应用尽管仍然是一一相应,可是是parentRDD中的某个区间的partitions相应到childRDD中的某个区间的partitions

典型的操作是union,多个parentRDD合并到一个childRDD,
故每一个parentRDD都相应到childRDD中的一个区间

须要注意的是,这里的union不会把多个partition合并成一个partition,而是的简单的把多个RDD中的partitions放到一个RDD里面,partition不会发生变化,

rdd參数,parentRDD

inStart參数,parentRDD的partitionId计算的起点位置。

outStart參数,childRDD中计算parentRDD的partitionId的起点位置,

length參数,parentRDD中partition的个数。

classRangeDependency[T](rdd: RDD[T], inStart: Int, outStart: Int, length:Int)

extendsNarrowDependency[T](rdd) {

overridedefgetParents(partitionId:
Int) = {

检查partitionId的合理性,此partitionId在childRDD的partitionId中的范围须要合理。

if(partitionId >= outStart && partitionId
< outStart +length) {

计算出ParentRDD的partitionId的值。

List(partitionId - outStart +inStart)

}else{

Nil

}

}

}

典型的应用场景union的场景把两个RDD合并到一个新的RDD中。

defunion(other: RDD[T]): RDD[T] =
newUnionRDD(sc,
Array(this,other))

使用union的,第二个參数是,两个RDD的array,返回值就是把这两个RDDunion后产生的新的RDD

ShuffleDependency关系:

此类依赖首先要求是Product2与PairRDDFunctions的k,v的形式,这样才干做shuffle,和hadoop一样。

其次,因为须要shuffle,所以当然须要给出partitioner,默认是HashPartitioner怎样完毕shuffle

然后,shuffle不象map能够在local进行,往往须要网络传输或存储,所以须要serializerClass

默认是JavaSerializer,一个类名,用于序列化网络传输或者以序列化形式缓存起来的各种对象。

默认情况下Java的序列化机制能够序列化不论什么实现了Serializable接口的对象,

可是速度是非常慢的,

因此当你在意执行速度的时候我们建议你使用spark.KryoSerializer而且配置Kryoserialization。

能够是不论什么spark.Serializer的子类。

最后,每一个shuffle须要分配一个全局的id,context.newShuffleId()的实现就是把全局id累加

classShuffleDependency[K, V](

@transientrdd: RDD[_ <: Product2[K, V]],

valpartitioner:Partitioner,

valserializerClass:String
= null)

extendsDependency(rdd.asInstanceOf[RDD[Product2[K,
V]]]) {

valshuffleId:Int
= rdd.context.newShuffleId()

}

生成RDD过程分析

生成rdd我们还是按wordcount中的样例来说明;

val
file= sc.textFile("/hadoop-test.txt")

valcounts
=file.flatMap(line=> line.split(" "))

)).reduceByKey(_+ _)

counts.saveAsTextFile("/newtest.txt")

1.首先SparkContext.textFile通过调用hadoopFile生成HadoopRDD实例,

textFile-->hadoopFile-->HadoopRDD,此时RDD的Dependency为Nil,一个空的列表。

此时的HadoopRDD为RDD<K,V>,每运行next方法时返回一个Pair,也就是一个KV(通过compute函数)

2.textFile得到HadoopRDD后,调用map函数,

map中每运行一次得到一个KV(compute中getNext,newNextIterator[(K,
V)] ),

中生成的RDD。

同一时候此RDD的Dependency为OneToOneDependency。

deftextFile(path: String, minSplits:
Int = defaultMinSplits):RDD[String] = {

hadoopFile(path,classOf[TextInputFormat], classOf[LongWritable], classOf[Text],

minSplits).map(pair =>pair._2.toString)

}

defmap[U: ClassTag](f: T => U): RDD[U]
= newMappedRDD(this,sc.clean(f))

中生成的HadoopRDD.

到多个新的item.生成FlatMappedRDD实例,

同一时候依据implicit隐式转换生成PairRDDFunctions。以下两处代码中的红色部分。

在生成FlatMappedRDD是,此时的上一层RDD就是2中生成的RDD。

同一时候此RDD的Dependency为OneToOneDependency。

classFlatMappedRDD[U:
ClassTag, T: ClassTag](

prev: RDD[T],

f:T => TraversableOnce[U])

extendsRDD[U](prev)

implicitdefrddToPairRDDFunctions[K:
ClassTag, V:ClassTag](rdd: RDD[(K, V)]) =

newPairRDDFunctions(rdd)

4.map函数,因为3中生成的FlatMappedRDD生成出来的结果,通过implicit的隐式转换生成PairRDDFunctions。

此时的map函数须要生成隐式转换传入的RDD<K,V>的一个RDD,

因此map函数的运行须要生成一个MappedRDD<K,V>的RDD,同一时候此RDD的Dependency为OneToOneDependency。

下面代码的红色部分。---RDD[(K,V)]。。

valcounts=
file.flatMap(line=>
line.split(
""))

.map(word=>
(word, 1)).reduceByKey(_+ _)

5.reduceByKey函数,此函数通过implicit的隐式转换中的函数来进行,主要是传入一个计算两个value的函数。

reduceByKey这类的shuffle的RDD时,终于生成一个ShuffleRDD,

此RDD生成的Dependency为ShuffleDependency。

详细说明在以下的reduceByKey代码中,

首先在每个map生成MapPartitionsRDD把各partitioner中的数据通过进行合并。合并通过Aggregator实例。

最后通过对合并后的MapPartitionsRDD,此RDD相当于mapreduce中的combiner,生成ShuffleRDD.

defreduceByKey(func: (V, V) => V):
RDD[(K, V)] = {

reduceByKey(defaultPartitioner(self),func)

}

defcombineByKey[C](createCombiner:
V => C,//创建combiner,通过V的值创建C

mergeValue: (C, V) =>C,//combiner已经创建C已经有一个值,把第二个的V叠加到C中,

mergeCombiners: (C, C) =>C,//把两个C进行合并,事实上就是两个value的合并。

partitioner:Partitioner,//Shuffle时须要的Partitioner

mapSideCombine: Boolean =true,//为了减小传输量,非常多combine能够在map端先做,

比方叠加,能够先在一个partition中把全部同样的key的value叠加,再shuffle

serializerClass: String =
null):RDD[(K, C)] = {

if(getKeyClass().isArray) {

if(mapSideCombine) {

thrownewSparkException("Cannot
use map-sidecombining with array keys.")

}

if(partitioner.isInstanceOf[HashPartitioner])
{

thrownewSparkException("Default
partitionercannot partition array keys.")

}

}

生成一个Aggregator实例。

valaggregator=
newAggregator[K, V, C](createCombiner, mergeValue, mergeCombiners)

假设RDD本身的partitioner与传入的partitioner同样,表示不须要进行shuffle

if(self.partitioner==
Some(partitioner)) {

生成MapPartitionsRDD,直接在map端当前的partitioner下调用Aggregator.combineValuesByKey。

把同样的key的value进行合并。

self.mapPartitionsWithContext((context,iter) => {

newInterruptibleIterator(context,
aggregator.combineValuesByKey(iter,context))

}, preservesPartitioning =
true)

}elseif(mapSideCombine)
{

生成MapPartitionsRDD,先在map端当前的partitioner下调用Aggregator.combineValuesByKey。

把同样的key的value进行合并。

combineValuesByKey中检查假设key相应的C假设不存在,通过createCombiner创建C,

否则key已经存在C时,通过mergeValue把新的V与上一次的C进行合并,

mergeValue事实上就是传入的reduceByKey(_+
_) 括号里的函数,与reduce端函数同样。

valcombined
=self.mapPartitionsWithContext((context, iter) => {

aggregator.combineValuesByKey(iter,context)

}, preservesPartitioning =
true)

生成ShuffledRDD,进行shuffle操作,由于此时会生成ShuffleDependency,又一次生成一个新的stage.

valpartitioned=
newShuffledRDD[K, C, (K, C)](combined,partitioner)

.setSerializer(serializerClass)

在上一步完毕,也就是shuffle完毕,又一次在reduce端进行合并操作。通过Aggregator.combineCombinersByKey

spark这些地方的方法定义都是通过动态载入运行的函数的方式,所以能够做到map端运行完毕后reduce再去运行兴许的处理。

由于函数在map时仅仅是进行了定义,reduce端才对函数进行运行。

partitioned.mapPartitionsWithContext((context,iter)
=> {

newInterruptibleIterator(context,
aggregator.combineCombinersByKey(iter,context))

}, preservesPartitioning =
true)

}else{

不运行map端的合并操作,直接shuffle,并在reduce中运行合并。

//Don't apply map-side combiner.

valvalues
=newShuffledRDD[K, V, (K, V)](self,partitioner).setSerializer(serializerClass)

values.mapPartitionsWithContext((context,iter) => {

newInterruptibleIterator(context,
aggregator.combineValuesByKey(iter,context))

}, preservesPartitioning =
true)

}

}

RDD的依赖关系的更多相关文章

  1. Spark RDD概念学习系列之RDD的依赖关系(宽依赖和窄依赖)(三)

    RDD的依赖关系?   RDD和它依赖的parent RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency). 1)窄依赖指的是每 ...

  2. 021 RDD的依赖关系,以及造成的stage的划分

    一:RDD的依赖关系 1.在代码中观察 val data = Array(1, 2, 3, 4, 5) val distData = sc.parallelize(data) val resultRD ...

  3. sparkRDD:第4节 RDD的依赖关系;第5节 RDD的缓存机制;第6节 DAG的生成

    4.      RDD的依赖关系 6.1      RDD的依赖 RDD和它依赖的父RDD的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency ...

  4. 【Spark】RDD的依赖关系和缓存相关知识点

    文章目录 RDD的依赖关系 宽依赖 窄依赖 血统 RDD缓存 概述 缓存方式 RDD的依赖关系 RDD和它依赖的父RDD的关系有两种不同的类型,即窄依赖(narrow dependency) 和宽依赖 ...

  5. 大数据学习day23-----spark06--------1. Spark执行流程(知识补充:RDD的依赖关系)2. Repartition和coalesce算子的区别 3.触发多次actions时,速度不一样 4. RDD的深入理解(错误例子,RDD数据是如何获取的)5 购物的相关计算

    1. Spark执行流程 知识补充:RDD的依赖关系 RDD的依赖关系分为两类:窄依赖(Narrow Dependency)和宽依赖(Shuffle Dependency) (1)窄依赖 窄依赖指的是 ...

  6. Spark RDD概念学习系列之rdd的依赖关系彻底解密(十九)

    本期内容: 1.RDD依赖关系的本质内幕 2.依赖关系下的数据流视图 3.经典的RDD依赖关系解析 4.RDD依赖关系源码内幕 1.RDD依赖关系的本质内幕 由于RDD是粗粒度的操作数据集,每个Tra ...

  7. Spark之RDD依赖关系及DAG逻辑视图

    RDD依赖关系为成两种:窄依赖(Narrow Dependency).宽依赖(Shuffle Dependency).窄依赖表示每个父RDD中的Partition最多被子RDD的一个Partition ...

  8. Spark-Core RDD依赖关系

    scala> var rdd1 = sc.textFile("./words.txt") rdd1: org.apache.spark.rdd.RDD[String] = . ...

  9. Spark RDD详解 | RDD特性、lineage、缓存、checkpoint、依赖关系

    RDD(Resilient Distributed Datasets)弹性的分布式数据集,又称Spark core,它代表一个只读的.不可变.可分区,里面的元素可分布式并行计算的数据集. RDD是一个 ...

随机推荐

  1. Effective java笔记5--通用程序设计

    一.将局部变量的作用域最小化      本条目与前面(使类和成员的可访问能力最小化)本质上是类似的.将局部变量的作用域最小化,可以增加代码的可读性和可维护性,并降低出错的可能性. 使一个局部变量的作用 ...

  2. CSS框架分析与网站的CSS架构

    框架(framework)是一个基本概念上的结构,用于去解决或者处理复杂的问题,是一种可复用的构架. 我们对CSS框架这个词比较陌生,但对于JavaScript框架就比较熟悉了,比如jQuery 但为 ...

  3. DTD 简介

    文档类型定义(DTD)可定义合法的XML文档构建模块.它使用一系列合法的元素来定义文档的结构.DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用. 内部的 DOCTYPE 声明 假如 DT ...

  4. bzoj1013

    这道题题解太多,只贴代码. #include<cstdio> #include<cmath> #include<algorithm> using namespace ...

  5. BPDU与PortFast

    启用了BPDU Guard特性的端口在收到BPDU的时候会使端口进入err-disable状态,从而避免桥接环路.一般BPDU Guard是和PortFast结合使用,在端口上启用了PortFast之 ...

  6. MATLAB图像处理工具箱

    下列表格中除了个别函数外,其余函数都是图像处理工具箱提供的关于图像处理的函数,现摘录到此以备查找. 表1 图像显示 函数名 功能说明 函数名 功能说明 colorbar 颜色条显示 montage 按 ...

  7. 最好的10本适用于初学者阅读的javaScript和jQuery书籍

    现在有许多方式学习新的内容,但是对于刚开始学习和寻找真正沉迷其中的平和状态的人而言,经典的纸质书籍依旧是首选.我发现阅读一本纸质书籍会让自己远离那些在使用电脑和平板时出现的令人不安的情绪.电子书和播客 ...

  8. tableView 显示区域偏移

    在SB拖了一个tableView , 在显示的时候显示区域和tableView的区域不一致, (UITableViewWrapperView 和 UITableView frame不一致) 在SB上看 ...

  9. No package identifier when getting name for resource number 0x00000000

    貌似在新版本的SDK下有时会出现标题的这个warning~  如下: 思前想后也不知道这个到底是说的哪里的问题,在逛谷歌的时候无意中发现有人说是因为xml中color的参数直接写成: android: ...

  10. CodeForces 711A Bus to Udayland (水题)

    题意:给定一个n*4的矩阵,然后O表示空座位,X表示已经有人了,问你是不能找到一对相邻的座位,都是空的,并且前两个是一对,后两个是一对. 析:直接暴力找就行. 代码如下: #pragma commen ...