Spark combineByKey算子详解

combineByKey:第一个传入的参数不再是初始值,意味着可以对数据的类型发生变化

def combineByKey[C](createCombiner: V => C,mergeValue: (C, V) => C,mergeCombiners: (C, C) => C): RDD[(K, C)]

createCombiner: 分区内,相同的key的value只执行一次,后续的value,执行mergeValue函数
mergeValue:分区内操作函数,相同key的剩余的value,和createCombiner得到的结果进行mergeValue操作
mergeCombiners: 分区间操作函数,相同的key进行mergeCombiners操作
RDD[(K, C)]:返回值类型,最后是元组啦,所以有多少个不同的key就有多少个元组
示例:根据key,求每种key的均值
思路:

  1. 首先求出每种key出现的次数
  2. 计算每种key的总和
  3. 将总和与key的次数形成一个元组,然后求均值
  4. 即希望的结果为(key,(sum,num))
上代码:
val z=sc.makeRDD(List(("a",1),("b",2),("a",2),("a",3),("b",0)),2)
z.glom.collect    // Array(Array((a,1), (b,2)), Array((a,2), (a,3), (b,0)))
var w=z.combineByKey(x=>(x,1),(x:(Int,Int),y:Int)=>(x._1+y,x._2+1),(x:(Int,Int),y:(Int,Int))=>(x._1+y._1,x._2+y._2))
w.collect   //Array[(String, (Int, Int))] = Array((b,(2,2)), (a,(6,3)))
var v=w.map(x=>(x._1,x._2._1/(x._2._2).toDouble))   //求均值
v.collect  //Array[(String, Double)] = Array((b,1.0), (a,2.0))

combineByKey代码解析:

  • z分为两个分区:
  • 第一分区:Array((a,1), (b,2))
  • 第二分区:Array((a,2), (a,3), (b,0))
  1. createCombiner阶段x=>(x,1):切记每个key的value只执行一次,第一分区有两个不同的key,所以createCombiner会执行两次;执行结果为:对a(1,1) 对于b(2,1);对偶元组的第一个参数为a的值,第二个参数为个数
  2. 第二分区执行createCombiner,有两个不同的key,所以createCombiner会执行两次;执行结果为:对a(2,1) 对于b(0,1)
  3. mergeValue阶段(x:(Int,Int),y:Int)=>(x._1+y,x._2+1):这里jvm推断不出来参数类型,所以需要自己写,不然会报错在这里插入图片描述
    第一个参数x就是createCombine得到的值,第二个参数y为相同key的剩余value值
    mergeValue阶段做的事情就是将createCombine得到的值,与同组剩余的key进行mergeValue段的函数操作;第一分区由于不存在同组的key,所以第一分区得到的结果不变,仍然为:对a(1,1) 对于b(2,1)。
    第二分区剩余(a,3)没有操作,所以将(2,1)和它进行操作,得到(5,2)
  4. mergeCombiners(x:(Int,Int),y:(Int,Int))=>(x._1+y._1,x._2+y._2)):对分区间同组的key进行操作,对于a,第一分区的结果为:a(1,1),第二分区的结果为(5,2),执行上面操作后,得到(6,3);对于b,第一分区的结果为(2,1),第二分区的结果为(0,1),执行操作,变为(2,2)
  5. 最后的返回值类型为RDD[(K, C)],所以结果为Array((b,(2,2)), (a,(6,3)))
  6. 最后就是求平均值了
    补充:用以前的算子进行解决
var z1=z.map(x=>(x._1,(x._2,1))).reduceByKey((x,y)=>(x._1+y._1,x._2+y._2))
z1.collect  //Array((b,(2,2)), (a,(6,3)))
var z2=z1.map(x=>(x._1,x._2._1/(x._2._2).toDouble))  //求均值
z2.collect  // Array((b,1.0), (a,2.0))

其实思路都差不多啦,都要将原始数据转成(key,(sum,num))格式

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值