Spark-之聚合算子的关系与区别

Spark-之聚合算子的关系与区别

  • reduceByKey
  • aggregateByKey
  • foldByKey
  • combineByKey

四种聚合方式都是在shuffle之前在分区内作预先聚合的操作,相对比groupByKey + map的方式,这些性能更加好,因为从map -> 磁盘 -> reduce这个过程中的mapstage的io减少了。

这些函数的过程分为:

1、分区内聚合map端聚合

2、分区间的shuffle聚合

下面通过4种不同的算子实现 wordcount操作!!

# 定义RDD
val rdd: RDD[(String, Int)] = sc.makeRDD(List(
    ("a", 1), ("a", 2), ("b", 2), ("a", 3)
), 2)


// TODO 1 reduceByKey(), 不会将相同key的value类型作转换,返回值的value类型与
val rdd1: RDD[(String, Int)] = rdd.reduceByKey(_ + _)
println(rdd1.collect().mkString(","))

// TODO 2 aggregateByKey(),可以将相同key的value类型作转换,zero参数的类型与返回值的类型是一致的
val rdd1: RDD[(String, Int)] = rdd.aggregateByKey(0)(
    _ + _, //分区内聚合
    _ + _  //分区间聚合
)

// TODO 3 foldByKey(),属于aggregateByKey的特殊版本,分区内聚合与分区间聚合的方式一样
val rdd1: RDD[(String, Int)] = rdd.foldByKey(0)(_ + _)


// TODO 4 combineByKey(), 相当于将aggregateByKey给初始运算参考值的操作,通过将第一个元素转换成对应的类型,然后参与后续运算
val rdd3: RDD[(String, Int)] = rdd.combineByKey(
    x => x, //运算前的类型转换
    (x: Int, v) => x + v, //分区内聚合
    (x: Int, y: Int) => x + y //分区间聚合
)

1 相同key的平均数(案例)

使用aggregateByKey和combineByKey配合map实现比较简单,主要过程如下:

  • 确定返回RDD元素类型为:(count,sum),平均数为 sum/count
  • 分区内操作,通过 初始值与当前value做merge
  • 分区间操作,通过将相同key的不同的(count,sum),(count,sum)进行merge

具体代码如下。

  • aggregateByKey
    // TODO 初始值的类型与RDD返回值的value的类型是一样的
    val value: RDD[(String, (Int, Int))] = rdd.aggregateByKey((0, 0)) // 给定初始值,这个也是返回值的value的类型
    (
      (tuple, v) => (tuple._1 + 1, tuple._2 + v),  //分区内作聚合(count+1,sum+v)
      (tuple1, tuple2) => (tuple1._1 + tuple2._1, tuple1._2 + tuple2._2) //分区间作聚合(count1+count2,sum1+sum2)
    )
    // 计算相同key的平均值
    val avgRDD: RDD[(String, Int)] = value.map {
      case (key, tuple) => (key, tuple._2 / tuple._1)
  • combineByKey
     // TODO 初始值的类型与RDD返回值的value的类型是一样的
	val rdd1: RDD[(String, (Int, Int))] = rdd.combineByKey(
      intVal => (1, intVal), //初始值进行转换,然后方便两两进行运算val => (count=1,sum=val)
      (t: (Int, Int), v) => (t._1 + 1, t._2 + v), //分区内作聚合(count+1,sum+v)
      (t1: (Int, Int), t2: (Int, Int)) => (t1._1 + t2._1, t1._2 + t2._2) //分区间作聚合(count1+count2,sum1+sum2)
    )
    val avgRDD: RDD[(String, Int)] = rdd1.map {
      case (key, t) => (key, t._2 / t._1)
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值