第五章_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()
  }
复制代码

 

posted @   学而不思则罔!  阅读(83)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示