第五章_Spark核心编程_Rdd_转换算子_keyValue型_【思考】reduceByKey、flodByKey、aggregateByKey、combineByKey 的区别?
1. 说明
/* * 思考 : * 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类型一致 * */
2. 需求 : List(("a", 88), ("b", 95), ("a", 91), ("b", 93), ("a", 95), ("b", 98)) 求每个 key 的平 均值
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() }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界