首先介绍combineByKey
这个算子 主要需要三个参数,第一个是对每个分区中每个key的第一个值 进行初始化,也就是每个分区内,有多少个key就会执行多少次这个初始化
object CombineByKeyTest01 { def main(args: Array[String]): Unit = { val conf=new SparkConf conf.setMaster("local").setAppName("test") val sc=new SparkContext(conf) val rdd1=sc.parallelize(List(("a","2"),("a","3"),("a","4"),("b","3"),("b","4")),2) rdd1.foreachPartition(f =>{ while(f.hasNext){ print(f.next()) } }) val rdd2=rdd1.combineByKey(x=>{println("fff=="+x);(x.toInt*2).toString()},(x1:String,x2:String)=>(x1.toInt+x2.toInt).toString(),(s1:String,s2:String)=>(s1.toInt+s2.toInt).toString()) rdd2.foreachPartition(f=>{ while(f.hasNext){ print(f.next()) } }) sc.stop() }第一个分区为(a,2)(a,3),第二个分区为(a,4)(b,3)(b,4)
对于第一个分区 ,首先执行第一步,即(a,4),然后聚合,得出(a,7)
对于第二个分区,首先执行第一步,(a,8),(b,6),(b,4)然后聚合得出(a,8),(b,10)
最后,对所有分区进行聚合,调用第三个参数对于的函数,得出(a,15),(b,10)
接下来介绍Aggregate
这个算子主要是三个参数,第一个参数是初始值,第二个参数进行分区内聚合,第三个参数是对每个分区最后的结果进行聚合
object AggregateTest01 { def main(args: Array[String]): Unit = { val conf=new SparkConf conf.setMaster("local").setAppName("test") val sc=new SparkContext(conf) val rdd1=sc.parallelize(List("1","2","3","4","5","6","7"),2) rdd1.foreachPartition(f =>{ while(f.hasNext){ print(f.next()) } }) //aggregate操作 val result=rdd1.aggregate("3")(seqOphyj,combOphyj) println(result) sc.stop() } //每个分区中 每个元素 乘以2 然后相加 进行分区内聚合操作 def seqOphyj(s1:String,s2:String):String={ val ss1=(2*s1.toInt+2*s2.toInt).toString() ss1 } //每个分区的结果 与初始值 进行相加操作 def combOphyj(s1:String,s2:String):String={ val ss1=(s1.toInt+s2.toInt).toString() ss1 } }第一个分区为1,2,3 第二个分区为4,5,6,7
对于第一个分区,首先进行第二个函数 即3*2+1*2=8 8*2+2*2=20 20*2+3*2=46
对于第二个分区,首先进行第二个函数, 3*2+4*2=14 14*2+5*2=38 38*2+6*2=88 88*2+7*2=190
然后进行调用第三个函数 3+46+190=239
接下来是AggregateByKey
这个算子基本和Aggregate类似,是对相同key的value进行聚合,但还是有区别的,区别在下面说。
object AggregateByKeyTest01 { def main(args: Array[String]): Unit = { val conf=new SparkConf conf.setMaster("local").setAppName("test") val sc=new SparkContext(conf) val rdd1=sc.parallelize(List(("1","2"),("1","3"),("1","4"),("2","3"),("2","4")),2) rdd1.foreachPartition(f =>{ while(f.hasNext){ print(f.next()) } }) val rdd2=rdd1.aggregateByKey("2")(seqOphyj, combOphyj) rdd2.foreachPartition(f =>{ while(f.hasNext){ print(f.next()) } }) sc.stop() } //每个分区中 每个元素 乘以2 然后相加 进行分区内聚合操作 def seqOphyj(s1:String,s2:String):String={ val ss1=(2*s1.toInt+2*s2.toInt).toString() println("seq="+s1+"&&"+s2+"====="+ss1) ss1 } //每个分区的结果 与初始值 进行相加操作 def combOphyj(s1:String,s2:String):String={ val ss1=(s1.toInt+s2.toInt).toString() println("com="+s1+"&&"+s2+"====="+ss1) ss1 } }第一个分区为(1,2)(1,3),第二个分区为(1,4)(2,3)(2,4)
首先计算第一个分区。对于key1,value为(2*2+2*2)*2+3*2=22
再计算第二个分区,对于key1,value为2*2+4*2=12,对于key2,value为(2*2+3*2)*2+4*2=28
计算第三个方法,为(1,34)(2,28),它与Aggregate的不同点在于第三个函数执行的时候。默认值不参与运算,而aggregate是参与的。