对combineByKey的理解,aggregateByKey

参数:(createCombiner: V => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C)
1.作用:对相同K,把V合并成一个集合。
2.参数描述:

(1)createCombiner:

combineByKey() 会遍历分区中的所有元素,因此每个元素的键要么还没有遇到过,要么就和之前的某个元素的键相同。如果这是一个新的元素,combineByKey()会使用一个叫作createCombiner()的函数来创建那个键对应的累加器的初始值

(2)mergeValue:

如果这是一个在处理当前分区之前已经遇到的键,它会使用mergeValue()方法将该键的累加器对应的当前值与这个新的值进行合并

(3)mergeCombiners:

由于每个分区都是独立处理的, 因此对于同一个键可以有多个累加器。如果有两个或者更多的分区都有对应同一个键的累加器, 就需要使用用户提供的 mergeCombiners() 方法将各个分区的结果进行合并。

3.需求:创建一个pairRDD,根据key计算每种key的均值。(先计算每个key出现的次数以及可以对应值的总和,再相除得到结果)
4.需求分析:
在这里插入图片描述

(1)创建一个pairRDD
scala> val input = 
sc.parallelize(Array(("a", 88), ("b", 95), ("a", 91), ("b", 93), ("a", 95), ("b", 98)),2)

input: org.apache.spark.rdd.RDD[(String, Int)] = 
ParallelCollectionRDD[52] at parallelize at <console>:26


(2)将相同key对应的值相加,同时记录该key出现的次数,放入一个二元组
scala> val combine = input.combineByKey((_,1),(acc:(Int,Int),v)=>(acc._1+v,acc._2+1),(acc1:(Int,Int),acc2:(Int,Int))=>(acc1._1+acc2._1,acc1._2+acc2._2))

combine: org.apache.spark.rdd.RDD[(String, (Int, Int))] = ShuffledRDD[5] at combineByKey at <console>:28

(3)打印合并后的结果
scala> combine.collect

res5: Array[(String, (Int, Int))] = Array((b,(286,3)), (a,(274,3)))

(4)计算平均值
scala> val result = combine.map{case (key,value) => (key,value._1/value._2.toDouble)}

result: org.apache.spark.rdd.RDD[(String, Double)] = MapPartitionsRDD[54] at map at <console>:30

(5)打印结果
scala> result.collect()
res33: Array[(String, Double)] = Array((b,95.33333333333333), (a,91.33333333333333))

理解:

1.首先是分区
我理解的,对这样的Array数组分区 就是根据个数来切分 分区的
比如上面我有两个分区 那么我就中间切开 将两边的数据放进两个分区,
对不对不知道、、、

通过glom算子查看分区结果:

定义2个分区
val input = sc.parallelize(Array(("a", 88), ("b", 95), ("a", 91), ("b", 93), ("a", 95), ("b", 98)),2)
-------------------------------------------------------------
分区结果
scala> input.glom.collect
res1: Array[Array[(String, Int)]] = Array(Array((a,88), (b,95), (a,91)), Array((b,93), (a,95), (b,98)))
-----------------------------------------------------
即 两个分区
Array((a,88), (b,95), (a,91))
Array((b,93), (a,95), (b,98))
-----------------------------------------

2.三个操作 (createCombiner,mergeValue,mergeCombiners)

前两个操作是分区内的,第三个操作是分区间

因为这个算子的名字combineByKey,是ByKey 通过key来分组操作的

对第一个操作的理解,createCombiner, 其实就是 初始化
(可以先看看上一篇博客的scala中的 Scala中的fold和reduce理解

那到底怎么初始化呢

首先 我们已经分区了 每个分区都是相同的操作,

所以第一个分区为例: Array((a,88), (b,95), (a,91))
ByKey嘛,所以 有两个key a, b

a : 88, 91

b : 95



这第一个操作createCombiner:

记住昂

是对相同的key取(第)一个,做初始化操作,

所以操作是这个 (_,1) 结果 就是
a : (88, 1) , 91
b : (95, 1)

注意 对于相同的key只挑选一个(一般是第一个)做初始化操作
这个操作的结果 就叫 acc
所以下一个操作的第一个参数 acc 的类型是 acc : (Int, Int)
第二个参数v 就是 相同key的其他值 比如 a 的 91

所以我们第二个操作mergeValue的逻辑根据题目要求可以是:

mergeValue
(acc:(Int,Int),v)=>(acc._1+v,acc._2+1)
对于相同key 值相加起来,此处每次操作加1 以记录次数


两个分区出来的结果是:
第一个分区:
a : ( 179, 2) ,
b : (95, 1)
第二个分区
a : (95,1)
b : (191, 2)


第三个操作mergeCombiners就是分区间的操作
(acc1:(Int,Int),acc2:(Int,Int))=>(acc1._1+acc2._1,acc1._2+acc2._2))
根据key将第一二个参数相加

结果的类型 [(String, (Int, Int))]

所以是 (a,(274,3)),(b,(286,3))


OK 很简单
感觉需要注意的:
1.就是第一 二个操作是分区内操作,第三个是分区间操作,
且第一个操作为初始化操作,
且在分区下相同的key只执行一次初始化操作,一般是挑选key的第一个V值作为操作对象


同理,
因为 aggregateByKey 底层调用的也是 combineByKey 所以两者是差不多的,

其第一个操作 zeroValue也是 :给每一个分区中的每一个key一个初始值;

参数:(zeroValue:U,[partitioner: Partitioner]) (seqOp: (U, V) => U,combOp: (U, U) => U)

  1. 作用:在kv对的RDD中,,按key将value进行分组合并,合并时,将每个value和初始值作为seq函数的参数,进行计算,返回的结果作为一个新的kv对,然后再将结果按照key进行合并,最后将每个分组的value传递给combine函数进行计算(先将前两个value进行计算,将返回结果和下一个value传给combine函数,以此类推),将key与计算结果作为一个新的kv对输出。
  2. 参数描述:
    (1)zeroValue:给每一个分区中的每一个key一个初始值;
    (2)seqOp:函数用于在每一个分区中用初始值逐步迭代value;
    (3)combOp:函数用于合并每个分区中的结果。
  3. 需求:创建一个pairRDD,取出每个分区相同key对应值的最大值,然后相加
  4. 需求分析
    在这里插入图片描述
    图1-aggregate案例分析
(1)创建一个pairRDD
scala> val rdd = sc.parallelize(List(("a",3),("a",2),("c",4),("b",3),("c",6),("c",8)),2)

rdd: org.apache.spark.rdd.RDD[(String, Int)] = 
ParallelCollectionRDD[0] at parallelize at <console>:24

(2)取出每个分区相同key对应值的最大值,然后相加
scala> val agg = rdd.aggregateByKey(0)(math.max(_,_),_+_)

agg: org.apache.spark.rdd.RDD[(String, Int)] =
 ShuffledRDD[1] at aggregateByKey at <console>:26
 
(3)打印结果
scala> agg.collect()
res0: Array[(String, Int)] = Array((b,3), (a,3), (c,12))
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值