请教Spark 中 combinebyKey 和 reduceByKey的传入函数参数的区别?
作者:连城
链接:https://www.zhihu.com/question/45420080/answer/99044117
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
由于 C 这个 类型参数是任意的,并不能从 testData 的类型直接推导出来,所以必须明确指定。只不过题主的例子是最简单的用 reduceByKey 就可以搞定的情况,也就是 V 和 C 完全相同,于是就看不出区别了
链接:https://www.zhihu.com/question/45420080/answer/99044117
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题主示例代码中 testData 这个 RDD 的类型是已经确定为 RDD[(String, Int)],然后通过 RDD.rddToRDDPairFunctions 这个隐式类型转换转为 PairRDDFunctions[String, Int],从而获得 reduceByKey 和 combineByKey 这两个 methods。
然后来对比下二者的函数签名:class PairRDDFunctions[K, V](...) {
def reduceByKey(func: (V, V) => V): RDD[(K, V)]
def combineByKey[C](
createCombiner: V => C,
mergeValue: (C, V) => C,
mergeCombiners: (C, C) => C): RDD[(K, C)]
}
可以看到 reduceByKey 的 func 参数的类型只依赖于 PairRDDFunction 的类型参数 V,在这个例子里也就是 Int。于是 func 的类型已经确定为 (Int, Int) => Int,所以就不需要额外标识类型了。
而 combineByKey 比 reduceByKey 更加通用,它允许各个 partition 在 shuffle 前先做 local reduce 得到一个类型为 C 的中间值,待 shuffle 后再做合并得到各个 key 对应的 C。
以求均值为例,我们可以让每个 partiton 先求出单个 partition 内各个 key 对应的所有整数的和 sum 以及个数 count,然后返回一个 pair (sum, count)。在 shuffle 后累加各个 key 对应的所有 sum 和 count,再相除得到均值:val sumCountPairs: RDD[(String, (Int, Long))] = testData.combineByKey(
(_: Int) => (0, 0L),
(pair: (Int, Long), value: Int) =>
(pair._1 + value, pair._2 + 1L),
(pair1: (Int, Long), pair2: (Int, Long)) =>
(pair1._1 + part2._1, pair2._2 + pair2._2)
)
val averages: RDD[String, Double] = sumCountPairs.mapValues {
case (sum, 0L) => 0D
case (sum, count) => sum.toDouble / count
}