请教Spark 中 combinebyKey 和 reduceByKey的传入函数参数的区别?

来源:互联网 发布:陕西师大远程网络教育 编辑:程序博客网 时间:2024/06/05 22:51



请教Spark 中 combinebyKey 和 reduceByKey的传入函数参数的区别?

代码如下val testData = sc.parallelize(Seq(("t1", 1), ("t1", 2), ("t1", 3), ("t2", 2), ("t2", 5)))val testDataCombine = testData.combineByKey(x=>x,(x:Int,y:Int)=>x+y,(x:Int,y:Int)=>x+y)val testDataReduce = testData.reduceByKey((x,y)=>x+y)这两个函数 在combineByKey 传入函数参数的时候 为什么一定要指定x ,y的Int类型,如果不指定会报错没发识别"+"这个方法符, 而reduceByKey的时候可以不用指定而进行系统推断。


作者:连城
链接: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}
由于 C 这个 类型参数是任意的,并不能从 testData 的类型直接推导出来,所以必须明确指定。只不过题主的例子是最简单的用 reduceByKey 就可以搞定的情况,也就是 V 和 C 完全相同,于是就看不出区别了

0 0
原创粉丝点击