算子三

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,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值