aggregateByKey,foldByKey,reduceByKey,combineByKey底层调用的都是combineByKeyWithClassTag,combineByKeyWithClassTag要传入三个函数,第一个函数是key的第一个value拿出来进行运算,是吧每一个分区内,相同key的value进行运算,第三个是进行全局运算的时候,将灭一个分区得到的,key相同的value进行运算,
注意combineByKey,与combineByKeyWithClassTag,都必须要指定第二个和第三个函数的类型,如果不指定类型是不能运行的,
combinByKey实现reduceByKey的功能,
combineByKey,底层调用
combineByKeyWithClassTag,分别传入三个参数,第一个是局部分组时,每个组的第一个参数,第二个函数传两个参数,第一个参数是每个组的第一个数,或者是计算期间的中间结果,第二个参数是另外一个要计算的参数,第三个函数传入两个key相同的局部聚合过得参数,属于全局聚合
//使用combineByKey实现reduceByKey的功能 //val reduced = wordAndOne.reduceByKey(_ + _) //传一个组里面第一个value怎么算,同一个组里面其他value怎么算 //不同组之间相同的key之间的value怎么算 val f1 = (x:Int)=>x val f2 = (m:Int,n:Int) =>m+n val f3 = (a:Int,b:Int)=>a+b //combinByKey聚合相同的key,对value进行相加 val reduced = wordAndOne.combineByKey(f1, f2, f3) reduced.saveAsTextFile("combinByKey-out") sc.stop()
使用groupByKey实现reduceByKey的功能
//使用groupByKey实现reduceByKey的功能,
1.先调用groupByKey,进行分组,然后调用mapValue() 进行对局部和全局进行聚合
groupBy与groupByKey区别
groupBy用起来相对灵活,数据可以不是对偶元组,因为里面的函数可以将数据变成一个个对偶元组,但是效率要比groupByKey要稍微低一点,因为后面在全局聚合进行shuffle的时候,不仅要shuffle 里面的key还要shuffle里面的value,而value包含了更多的数据,
//使用groupByKey实现reduceByKey的功能,
//mapValue就是在处理数据的时候,不管Key,直接把value处理好之后,就把key就合到一起
//这一句话是吧key相同的数据放到一起,然后然后value=1放到一个特殊的集合里面
val grouped = wordAndOne.groupByKey()
//直接对valu进行求和操作
val result: RDD[(String, Int)] = grouped.mapValues(_.sum)
result.saveAsTextFile("groupByKey-out")
sc.stop()
使用new ShuffleRDD实现类似reduceByKey的功能,
1.new ShuffleRDD( 指定key为String,类型,value为int类型,聚合相加后的value也为Int类型
2.把局部处理逻辑定义为true
3.设置一个聚合器,在设置聚合器之前先定义三个函数
第一个函数是每个集合第一个要穿进行的数,
第二个函数有两个参数:第一个为每个函数第一次传进去的参数,或者是中间值,第二个参数是另外一个需要传进去的参数
第三个参数:在shulffleRDD中做全局聚合是时,需要两个key相同的局部聚合重的参数值,然后分到同一个组后再进行聚合
//使用自己new ShuffleRDD实现类似reduceByKey的功能
//ShuffleRDD先要指定key为String类型,然后要指定Value类型为(Int) 指定局部聚合后额value类型(Int),然后装到
//combineBuffer里面
val shuffleRDD: ShuffledRDD[String, Int, Int] = new ShuffledRDD[String, Int, Int](
wordAndOne,
new HashPartitioner(wordAndOne.partitions.length)
)
//需要先定义局部处理逻辑
shuffleRDD.setMapSideCombine(true)
//设置一个聚合器
val f1 = (x:Int)=>x
val f2 = (m:Int,n:Int)=>m+n
val f3 = (a:Int,b:Int)=>a+b
shuffleRDD.setAggregator(new Aggregator[String,Int,Int](
f1,f2,f3
))
shuffleRDD.saveAsTextFile("shuffleRDD-out")
sc.stop()
/**
* 在没有设置聚合器的情况下
* (spark,1)
* (hadoop,1)
* (spark,1)
* (spark,1)
* (hbase,1)
* (spark,1)
* (hadoop,1)
*/
/**
* 在有聚合器的情况下
spark,4)
(hadoop,2)
(hbase,1)
*/
foldByKey:底层第一个括号会传入一个初始值,然后再传入一个分区器,第二个括号会传入一个局部或全局聚合的函数
初始值只在局部聚合的时候使用,也就是每一个数据在局部聚合的时候都要加初始值
val conf = new SparkConf().setAppName("ReduceByKey").setMaster("local[*]")
val sc = new SparkContext(conf)
val words = sc.parallelize(
List(
"spark", "hadoop", "hive", "spark",
"spark", "hbase", "flink", "hive",
"kafka", "kafka", "spark", "hive",
"hadoop", "flink", "hive", "flink"
), 4
)
val wordAndOne: RDD[(String, Int)] = words.map((_, 1))
//foldByKey与ReduceByKey除了多了一个初始值其余的都一样
val result = wordAndOne.foldByKey(100)(_ + _)
result.saveAsTextFile("fold-out")
sc.stop()
/**
* 底层第一个括号会传入一个初始值,然后再传入一个分区器,
* 第二个括号会传入一个局部或全局聚合的函数
* 初始值只在局部聚合的时候使用,也就是每一个数据在局部聚合的时候都要加初始值,
*/
aggregateByKey () 也可以实现数据的分组聚合,里面传入两个函数,第一个是分组聚合,第二个是全局分组聚合,
/**
* 底层第一个括号会传入一个初始值,然后再传入一个分区器,
* 第二个括号会传入一个局部或全局聚合的函数
* 初始值只在局部聚合的时候使用,也就是每一个数据在局部聚合的时候都要加初始值,
*/
val wordAndOne: RDD[(String, Int)] = words.map((_, 1))
//aggregateByKey要传入两个函数,第一个是局部聚合函数,第二个是全局聚合函数
//局部聚合和全局聚合的逻辑可以不一样
val result: RDD[(String, Int)] = wordAndOne.aggregateByKey(0)(_ + _, _ + _)
result.saveAsTextFile("aggregate-out")
sc.stop()
aggregateByKey实现分组聚合操作
求所有元组数据每个分组最大值之和
Max.math(_,_) 比较元组内数据的大小,,然后再求和,
这样可知,初始值在内次进行局部求最大值的时候,都进行比较,所有有多少个分区初始值就拿出来比较多少次.
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("ReduceByKey").setMaster("local[*]")
val sc = new SparkContext(conf)
val wordAndCount: RDD[(String, Int)] = sc.parallelize(
List(("spark", 5), ("hadoop", 2), ("spark", 3), ("hive", 4),
("spark", 12), ("hadoop", 4), ("spark", 1), ("hive", 2)
), 2)
//val wordAndOne: RDD[(String, Int)] = wordAndCount.map((_, 1))
//求每一个分区里面的最大值
//注意这里设置的初始值也要参与比较,10与第一行的值比较最大则最后显示10,
//与第二行比较的值12最大,所以spark在最后得出的结果为22
//流程是先对每个分区进行求取最大值,然后再全局聚合的时候,对每个分区相同key的值进行相加
val result2 = wordAndCount.aggregateByKey(10)(Math.max(_, _), _ + _)
result2.saveAsTextFile("aggregate-out3")
sc.stop()
}
RDD里面是k-v类型元组的就可以调用reduceByKey,