Job逻辑执行图
典型的Job逻辑执行图如上所示,经过下面四个步骤可以得到最终执行结果:
1.从数据源(可以是本地file,内存数据结构, HDFS,HBase等)读取数据创建最初的RDD。
2.对RDD进行一系列的transformation()操作,每一个transformation()会产生一个或多个包含不同类型RDD。
3.对最后的final RDD进行action()操作,每个partition计算后产生结果result。
4.将result回送到driver端,进行最后的f(list[result])计算。
一些典型的transformation()的计算过程及数据依赖图
1) union(otherRDD)
union()将两个RDD简单合并在一起,不改变partition里面的数据。没有shuffle过程。该操作可以用来处理来自多个数据源的日志文件,若输入的RDD中有重复数据,Spark的union()也会包含这些重复数据(如有必要,可用distinct()去重)
2) groupByKey(numPartitions)
groupByKey()只需要将Key相同的records聚合在一起,一个简单的shuffle过程就可以完成。ShuffledRDD中的compute()只负责将属于每个partition的数据fetch过来,之后使用mapPartitions()操作进行aggregate,生成MapPartitionsRDD,到这里groupByKey()已经结束。最后为了统一返回值接口,将value中的ArrayBuffer[]数据结构抽象化成Iterable[]。
3) reduceyByKey(func, numPartitions)
reduceyByKey()相当于传统的MapReduce,整个数据流也与Hadoop中的数据流基本一样。reduceyByKey()默认在map端开启combine(),因此在shuffle之前先通过mapPartitions操作进行combine,得到MapPartitionsRDD,然后shuffle得到ShuffledRDD,然后再进行reduce(通过aggregate+mapPartitions()操作来实现)得到MapPartitionsRDD。
4) distinct(numPartitions)
distinct()功能是deduplicate RDD中的所有的重复数据。由于重复数据可能分散在不同的partition里面,因此需要shuffle来进行aggregate后再去重。然而,shuffle要求数据类型是 <K, V>。如果原始数据只有Key(比如例子中record只有一个整数),那么需要补充成<K,null>。这个补充过程由map()操作完成,生成MappedRDD。然后调用上面的reduceByKey()来进行shuffle,在map端进行combine,然后reduce进一步去重,生成MapPartitionsRDD。最后,将<K,null>还原成K,仍然由map()完成,生成MappedRDD。蓝色的部分就是调用的reduceByKey()。
5) cogroup(otherRDD, numPartitions)
cogroup()是对多个共享同一个键的RDD进行分组,与groupByKey()不同,cogroup()要aggregate两个或两个以上的RDD。
6) intersection(otherRDD)
intersection()功能是抽取出RDD a和RDD b中的公共数据,会去掉所有重复元素。先使用map()将RDD[T]转变成RDD[(T,null)]。接着,进行a.cogroup(b),蓝色部分与前面的cogroup()一样。之后再使用filter()过滤掉[iter(groupA()),iter(groupB())]中groupA或groupB为空的records,得到FilteredRDD。最后,使用keys()只保留key即可,得到MappedRDD。
7) join(otherRDD, numPartitions)
join()将两个RDD[(K, V)] 按照SQL 中的join 方式聚合在一起。只有在两个pairRDD种都存在的键才输出,当一个输入对应的某个键有多个值时,生成的pairRDD会包括来自两个输入RDD的每一组相对应的记录。与intersection()类似,首先进行cogroup(),得到<K,(Iterable[V1],Iterable[V2])>类型的MappedValuesRDD,然后对 Iterable[V1]和Iterable[V2]做笛卡尔集,并将集合flat()化。
8) sortByKey(ascending, numPartitions)
sortByKey()将 RDD[(K,V)] 中的records按 key 排序,ascending=true表示升序,false表示降序。目前 sortByKey()的数据依赖很简单,先使用shuffle将records聚集在一起(放到对应的partition里面),然后将partition内的所有records按key排序,最后得到的MapPartitionsRDD中的records就有序了。
9) cartesian(otherRDD)
Cartesian对两个RDD做笛卡尔集,生成的CartesianRDD中partition个数 = partitionNum(RDD a) *partitionNum(RDD b)。笛卡尔积在我们希望考虑所有可能的组合的相似度时比较有用,比如计算个用户对各种产品的预期兴趣程度。注意求大规模RDD的笛卡尔积开销巨大。
10) coalesce(numPartitions,shuffle =false)
coalesce()可以将parent RDD的partition个数进行调整,比如从5个减少到3个,或者从5个增加到10个。需要注意的coalesce()可以将parent RDD的partition个数进行调整,比如从5个减少到3个,或者从5个增加到10个。需要注意的是当shuffle=false的时候,是不能增加partition个数的(不能从5个变为10个)。可以使用JAVA或者scala中的rdd.partitions.size查看RDD的分区。
11) repartition(numPartitions)
等价于coalesce(numPartitions, shuffle=true),对数据重新分区是代价相对比较大的操作。
————————————————
版权声明:本文为CSDN博主「guyy_moon」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/faan0966/article/details/79995428