源码有两种方式:
/**
*
* @param createCombiner
* @param mergeValue
* @param mergeCombiners
* @tparam C
* @return
*/
def combineByKey[C](
createCombiner: V => C,
mergeValue: (C, V) => C,
mergeCombiners: (C, C) => C): RDD[(K, C)] = self.withScope {
combineByKeyWithClassTag(createCombiner, mergeValue, mergeCombiners)(null)
/**
*
* @param createCombiner
* @param mergeValue
* @param mergeCombiners
* @param partitioner
* @param mapSideCombine
* @param serializer
* @tparam C
* @return
*/
def combineByKey[C](
createCombiner: V => C,
mergeValue: (C, V) => C,
mergeCombiners: (C, C) => C,
partitioner: Partitioner,
mapSideCombine: Boolean = true,
serializer: Serializer = null): RDD[(K, C)] = self.withScope {
combineByKeyWithClassTag(createCombiner, mergeValue, mergeCombiners,
partitioner, mapSideCombine, serializer)(null)
}
}
第一个参数,如果分区中元素的key是第一次出现,那么就使用第一个参数应用到这个元素中,如果遇到的元素经过了第一个参数的处理,那么就让第二个参数应用到已存在的元素和这个元素上,第三个参数是将所有分区的计算结果按照key进行汇总分组计算。
scala代码测试:
def main(args: Array[String]): Unit = {
Logger.getLogger("org").setLevel(Level.OFF)
val spark = SparkSession.builder().master("local").getOrCreate()
val initialScores = List(("A", 88.0), ("A", 95.0), ("B", 93.0), ("B", 95.0), ("B", 98.0),("A", 91.0))
val d1 = spark.sparkContext.parallelize(initialScores,2)
println(d1.getNumPartitions)
type MVType = (Int, Double) //定义一个元组类型(科目计数器,分数)
d1.combineByKey(
score =>{
println("第一个",score)
(1, score)
} ,
(c1: MVType, newScore) => {
println("第二个",c1._1 + 1,c1._2,newScore)
(c1._1 + 1, c1._2 + newScore)
},
(c1: MVType, c2: MVType) =>{
println("第三个",c1._1 ,c1._2 , c2._1, c2._2)
(c1._1 + c2._1, c1._2 + c2._2)
}
).map { case (name, (num, score)) => (name, score / num) }.collect.foreach(println)
}
计算结果:
(第一个,88.0)
(第二个,2,88.0,95.0)
(第一个,93.0)
(第一个,95.0)
(第二个,2,95.0,98.0)
(第一个,91.0)
(第三个,1,93.0,2,193.0)
(第三个,2,183.0,1,91.0)
(B,95.33333333333333)
(A,91.33333333333333)
代码详解:
RDD分为两个分区:
第一分区:(“A”, 88.0), (“A”, 95.0), (“B”, 93.0)
第二分区:(“B”, 95.0), (“B”, 98.0),(“A”, 91.0)
首先第一个分区的计算:
(第一个,88.0)
(第二个,2,88.0,95.0)
(第一个,93.0)
其次第二个分区的计算:
(第一个,95.0)
(第二个,2,95.0,98.0)
(第一个,91.0)
第一个分区得到的是(“A”, (2,88+95)),第二个分区得到的是(“A”, (1,91.0)),然后用第三个参数应用到这两个结果中(汇总分组统计),得到(“A”,(2+1,89+95+91));
第一个分区得到的是(“B”, (1,93)),第二个分区得到的是(“B”, (2,95+98)),然后用第三个参数应用到这两个结果中(汇总分组统计),得到(“B”,(1+2,93+95+98));
返回值:
(第三个,1,93.0,2,193.0)
(第三个,2,183.0,1,91.0)
(B,95.33333333333333)
(A,91.33333333333333)