这一节我们会继续介绍和key相关的transformations算子。
GroupByKey
Y = X.groupByKey(): RDD[(K, V)] -> RDD[(K, Array[V])]
GroupByKey算子的计算过程是将相同key值的value组成一个数组并返回。

GroupByKey RDD实现
-
Y.partitions() -> Array[Partition]:
返回按照key的取值空间组成的新的分区集合。 -
Y.iterator(p: Partition, parents: Array[RDD[(K, V)]]) -> Iterator[(K, Array[V])]
遍历所有的依赖分区,选择在当前分区范围的key,组成key和value数组的pair,这是一个shuffle的过程。 -
Y.dependencies() -> Array[Dependency]
依赖所有输入的分区,返回k个输出分区。
ReduceByKey
Y = X.reduceByKey(f: (V, V) -> V): RDD[(K, V)] -> RDD[(K, V)]
ReduceByKey算子的计算过程是将相同key的value,经过传入的计算函数后得到最终的计算结果,和GroupByKey算子相比,多了一步值和值之间计算的过程。

cogroup
X.cogroup(Y: RDD[(K, W)]): RDD[(K, V)] -> RDD[(K, (Array[V], Array[W]))]
cogroup算子,将两个RDD中相同key的数据进行分区,返回一个triple,分别为key,第一个RDD的value数组,第二个RDD的value数组。可以看出这个算子可以用于join两个RDD的数据,只需继续计算triple中两个数组的笛卡尔积即可。

join
X.join(Y: RDD[(K, W)]): RDD[(K, V)] -> RDD[(K, V, W)]
和cogroup的计算类似,join算子将两个RDD中相同key的值在同一行输出结果,通过改变某个key只在一边RDD中有数据的处理方式,可以扩展出left join, right join, full join等算子。

Group Transformations的特点
Shuffle
Group类的算子都需要数据进行shuffle的操作,因此在shuffle的过程也会对网络、内存等带来很大的消耗。GroupByKey算子的shuffle过程如下:

宽依赖和窄依赖
由于可能存在shuffle的过程,我们将RDD的依赖关系划分为宽依赖和窄依赖。
- 窄依赖:每个parent分区最多只有一个child分区,例如filter算子;
- 宽依赖:每个parent分区都有超过一个child分区,例如groupByKey算子。

所有Transformations算子:
- map
- filter
- flatMap
- mapPartitions
- mapPartitionsWithIndex
- mapValues
- sample
- distinct
- union
- intersection
- groupByKey
- reduceByKey
- aggregateByKey
- sortByKey
- join
- cogroup
- cartesian
- coalesce
- repartition
- ...
MapReduce到Spark
使用RDD的flatMap和groupByKey的算子,可以完成类似MapReduce的map和reduce的函数功能,举例如下:
Y = X.flatMap(m).groupByKey().flatMap(r)
X : RDD[T]
.flatMap(m) : RDD[(K, V)], m: T -> Array[(K, V)]
.groupByKey() : RDD[(K, Array[V])]
.flatMap(r) : RDD[U], r: (K, Array[V]) -> Array[U]

小结
Transformation是RDD的一类算子,通过已有的RDD,经过不同的计算方式,得到新的RDD。Transformations的执行是懒惰的,只有在数据真正需要的时候才会计算。Transformations中RDD的依赖关系分为宽依赖和窄依赖。MapReduce的过程也可以通过transformations实现。复杂的transformations过程,例如join和cogroup也可以实现。
网友评论