我有一个RDD
中的一个mutable.Map[(Int, Array[Double])]
,我想将映射减少Int
并找到数组元素的均值。
例如,我有:
Map[(1, Array[0.1, 0.1]), (2, Array[0.3, 0.2])]
Map[(1, Array[0.1, 0.4])]
我想要什么:
Map[(1, Array[0.1, 0.25]), (2, Array[0.3, 0.2])]
问题是我不知道reduce
在地图之间的工作方式,此外,我还必须对每个分区进行处理,将结果收集到驱动程序中,并在那里进行缩减。我找到了foreachPartition
方法,但不知道是否可以在这种情况下使用。
有什么想法吗?
答案 0 :(得分:1)
您可以使用combineByKey
来完成此操作:
val rdd = ss.sparkContext.parallelize(Seq(
Map((1, Array(0.1, 0.1)), (2, Array(0.3, 0.2))),
Map((1, Array(0.1, 0.4)))
))
// functions for combineByKey
val create = (arr: Array[Double]) => arr.map( x => (x,1))
val update = (acc : Array[(Double,Int)], current: Array[Double]) => acc.zip(current).map{case ((s,c),x) => (s+x,c+1)}
val merge = (acc1 : Array[(Double,Int)],acc2:Array[(Double,Int)]) => acc1.zip(acc2).map{case ((s1,c1),(s2,c2)) => (s1+s2,c1+c2)}
val finalMap = rdd.flatMap(_.toList)
// aggreate elementwise sum & count
.combineByKey(create,update,merge)
// calculate elementwise average per key
.map{case (id,arr) => (id,arr.map{case (s,c) => s/c})}
.collectAsMap()
// finalMap = Map(2 -> Array(0.3, 0.2), 1 -> Array(0.1, 0.25))