/*
* 思考 :
* reduceByKey、flodByKey、aggregateByKey、combineByKey 的区别?
* 本质区别 : Map端聚合和Reduce聚合规则是否相同,是不是要在Map的实现合并器
*
* 1. reduceByKey
* 1. 定义
* def reduceByKey(partitioner: Partitioner, func: (V, V) => V): RDD[(K, V)]
* 2. 操作流程
* 1. 在每个分区节点上将 数据根据key 分组 (相当于Mr中的map方法)
* 输出 key,iter(value1,value2...)
* 2. 在每个分区节点上将 分组后的数据 进行合并 (相当于Mr中的map端合并)
* 合并流程
* 输入 : key,iter(value1,value2...)
* func(func(value1,value2),value3)... => 聚合结果和value1类型一致
* 从左往右依次聚合
* 输出 key,value
* 3. 每个分区处理完后, reduce端会拉取处理结果,并对数据根据key 进行reduce操作 (相当于Mr中的reduce方法)
* 合并流程
* 输入 : key,iter(value1,value2...)
* func(func(value1,value2),value3)...
* 从左往右依次聚合
* 输出 key,value
* 4. 对处理完的结果数据,根据 指定的分区器,将结果分区(可选)
* 不指定时,使用默认分区器,分区个数和父Rdd保持一致
* 3. note
* 1. reduceByKey相当于Mr程序,开启了Map端合并,且合并规则和reduce规则相同
* 2. reduceByKey 只能将 Rdd[K,V]转换成 Rdd[K,V]
* Key、Value的类型不会改变
* 示例 Rdd[String,Int] reduceByKey处理后 Rdd[String,Int]
* 4. 使用场景
* 1. 对key,value型的Rdd 按Key分组聚合
* 且Map端聚合规则和Reduce端聚合规则相同
* 且聚合结果和聚合前value类型一致
*
* 2. flodByKey
* 1. 定义
* def foldByKey(zeroValue: V,partitioner: Partitioner)(func: (V, V) => V): RDD[(K, V)]
* 2. 操作流程
* 1. 在每个分区节点上将 数据根据key 分组 (相当于Mr中的map方法)
* 输出 key,iter(value1,value2...)
* 2. 在每个分区节点上将 分组后的数据 进行合并 (相当于Mr中的map端合并)
* 合并流程
* 输入 : key,iter(value1,value2...)
* func(func(zeroValue,value1),value2)... => 聚合结果和value1类型一致
* 从左往右依次聚合
* 输出 key,value
* 3. 每个分区处理完后, reduce端会拉取处理结果,并对数据根据key 进行reduce操作 (相当于Mr中的reduce方法)
* 合并流程
* 输入 : key,iter(value1,value2...)
* func(func(zeroValue,value1),value2)...
* 从左往右依次聚合
* 输出 key,value
* 4. 对处理完的结果数据,根据 指定的分区器,将结果分区(可选)
* 不指定时,使用默认分区器,分区个数和父Rdd保持一致
* 3. note
* 1. foldByKey相当于Mr程序,开启了Map端合并,且合并规则和reduce规则相同
* 2. foldByKey 只能将 Rdd[K,V]转换成 Rdd[K,V]
* Key、Value的类型不会改变
* 示例 Rdd[String,Int] reduceByKey处理后 Rdd[String,Int]
* 4. 使用场景
* 1. 对key,value型的Rdd 按Key分组聚合
* 且Map端聚合规则和Reduce端聚合规则相同
* 且聚合结果和聚合前value类型一致
* 2. foldByKey 和 reduceByKey 的区别
* foldByKey : 有zeroValue参与value的聚合
* reduceByKey : 没有zeroValue参与value的聚合
*
* 3. AggregateByKey
* 1. 定义
* def aggregateByKey[U: ClassTag](zeroValue: U, partitioner: Partitioner)
* (seqOp: (U, V) => U,combOp: (U, U) => U): RDD[(K, U)]
* 2. 操作流程
* 1. 在每个分区节点上将 数据根据key 分组 (相当于Mr中的map方法)
* 输出 key,iter(value1,value2...)
* 2. 在每个分区节点上将 分组后的数据 进行合并 (相当于Mr中的map端合并)
* 合并流程
* 输入 : key,iter(value1,value2...)
* seqOp(seqOp(zeroValue,value1),value2)... => 聚合结果为zeroValue
* 从左往右依次聚合
* 输出 key,value
* 3. 每个分区处理完后, reduce端会拉取处理结果,并对数据根据key 进行reduce操作 (相当于Mr中的reduce方法)
* 合并流程
* 输入 : key,iter(value1,value2...)
* combOp(combOp(zeroValue,value1),value2)...
* 从左往右依次聚合
* 输出 key,value
* 4. 对处理完的结果数据,根据 指定的分区器,将结果分区(可选)
* 不指定时,使用默认分区器,分区个数和父Rdd保持一致
* 3. note
* 1. aggregateByKey 相当于Mr程序,开启了Map端合并,且合并规则和reduce规则不同
* 2. aggregateByKey 可以将 Rdd[K,V]转换成 Rdd[K,C]
* Key、Value的类型不会改变
* 示例 Rdd[String,Int] reduceByKey处理后 Rdd[String,List]
* 4. 使用场景
* 1. 对key,value型的Rdd 按Key分组聚合
* 且Map端聚合规则和Reduce端聚合规则可以不相同
* 且聚合结果和zeroValue类型一致
* 2. foldByKey 和 reduceByKey 和 aggregateByKey 的区别
* foldByKey : 有zeroValue参与value的聚合
* reduceByKey : 没有zeroValue参与value的聚合
* aggregateByKey : 有zeroValue参与value的聚合
* Map端聚合与 zeroValue类型一致
*
* 4. CombineByKey
* 1. 定义
* def combineByKey[C](createCombiner: V => C,
* mergeValue: (C, V) => C,
* mergeCombiners: (C, C) => C,
* partitioner: Partitioner,
* serializer: Serializer = null): RDD[(K, C)]
* 2. 操作流程
* 1. 在每个分区节点上将 数据根据key 分组 (相当于Mr中的map方法)
* 输出 key,iter(value1,value2...)
* 2. 在每个分区节点上将 分组后的数据 进行合并 (相当于Mr中的map端合并)
* 合并流程
* 输入 : key,iter(value1,value2...)
* 聚合前 先将value转换数据结果
* createCombiner: V => C
* mergeValue(mergeValue(createCombiner: V => C,value1),value2)... => 聚合结果为createCombiner结果类型
* 从左往右依次聚合
* 输出 key,value
* 3. 每个分区处理完后, reduce端会拉取处理结果,并对数据根据key 进行reduce操作 (相当于Mr中的reduce方法)
* 合并流程
* 输入 : key,iter(value1,value2...)
* mergeCombiners(mergeCombiners(value1,value1),value2)...
* 从左往右依次聚合
* 输出 key,value
* 4. 对处理完的结果数据,根据 指定的分区器,将结果分区(可选)
* 不指定时,使用默认分区器,分区个数和父Rdd保持一致
* 3. note
* 1. CombineByKey 相当于Mr程序,开启了Map端合并,且合并规则和reduce规则不同
* 2. CombineByKey 可以将 Rdd[K,V]转换成 Rdd[K,C]
* Key、Value的类型不会改变
* 示例 Rdd[String,Int] reduceByKey处理后 Rdd[String,List]
* 4. 使用场景
* 1. 对key,value型的Rdd 按Key分组聚合
* 且Map端聚合规则和Reduce端聚合规则可以不相同
* 且聚合结果和zeroValue类型一致
* 2. foldByKey 和 reduceByKey 和 aggregateByKey 和 的区别
* foldByKey : 有zeroValue参与value的聚合
* reduceByKey : 没有zeroValue参与value的聚合
* aggregateByKey : 有zeroValue参与value的聚合
* Map端聚合与 zeroValue类型一致
* CombineByKey : 有zeroValue参与value的聚合
* Map端聚合与 zeroValue类型一致
* */
object combineByKeyPakTest1 extends App {
val sparkconf: SparkConf = new SparkConf().setMaster("local").setAppName("distinctTest")
val sc: SparkContext = new SparkContext(sparkconf)
val rdd = sc.makeRDD(List(("a", 88), ("b", 95), ("a", 91), ("b", 93), ("a", 95), ("b", 98)), 2)
/*groupByKey*/
//分组
private val rdd1: RDD[(String, Iterable[Int])] = rdd.groupByKey()
//求平均数
private val rdd3: RDD[(String, Int)] = rdd1.map(
(tp: (String, Iterable[Int])) => (tp._1, tp._2.sum / tp._2.size)
)
/*aggregateByKey*/
//设置 zeroValue类型 (key, value) key用来记录次数 value用来累加值
// (b,(3,286)),(a,(3,274))
private val rdd4: RDD[(String, (Int, Int))] = rdd.aggregateByKey((0, 0))(
(zeroValue, value1) => (zeroValue._1 + 1, zeroValue._2 + value1)
, (zeroValue, tp) => (zeroValue._1 + tp._1, zeroValue._2 + tp._2)
)
private val rdd5: RDD[(String, Int)] = rdd4.map(
tp => (tp._1, tp._2._2 / tp._2._1)
)
/*foldByKey*/
private val rdd6 = rdd.map(
tp => (tp._1, (1, tp._2))
).foldByKey((0, 0))(
(zeroValue, tp) => (zeroValue._1 + tp._1, zeroValue._2 + tp._2)
).map(
tp => (tp._1, tp._2._2 / tp._2._1)
)
/*combineByKey*/
private val rdd7: RDD[(String, Int)] = rdd.combineByKey(
value => (1, value)
, (tp: (Int, Int), value) => (tp._1 + 1, tp._2 + value)
, (tp1: (Int, Int), tp2: (Int, Int)) => (tp1._1 + tp2._1, tp1._2 + tp2._2)
).map(
tp => (tp._1, tp._2._2 / tp._2._1)
)
println(s"${rdd3.collect().mkString(",")}")
println(s"${rdd5.collect().mkString(",")}")
println(s"${rdd6.collect().mkString(",")}")
println(s"${rdd7.collect().mkString(",")}")
/*
*
* (b,95),(a,91)
*
* 13 56 = 15/4 = 3...3
* 4/2 11/2 = 2 + 11/2 =
* 1 + 14/3 = 17/3
*
*
*
*
* */
sc.stop()
}