一、聚合方法
大型数据集中,为了减少shuffle的数据量,相对于groupByKey来说,使用reduceByKey、combineByKey以及foldByKey 会是更好的选择
- 数据
def create_pair(t3):
return (t3[0], int(t3[2]))
def create_pair_sumcnt(t3):
name = t3[0]
number = int(t3[2])
return (name, (number, 1))
spark = SparkSession.builder.appName('avg_by_key').getOrCreate()
list_of_tuples = [('alex', 'Sunnyvale', 25),
('alex', 'Sunnyvale', 33),
('alex', 'Sunnyvale', 45),
('alex', 'Sunnyvale', 63),
('mary', 'Ames', 22),
('mary', 'Cupertino', 66),
('mary', 'Ames', 20),
('bob', 'Ames', 26)]
rdd = spark.sparkContext.parallelize(list_of_tuples)
rdd_pair = rdd.map(lambda t: create_pair(t))
rdd_pair1 = rdd.map(lambda x: create_pair_sumcnt(x))
1.1 aggregateByKey
- 预设初始值
zero_tuple = (0, 0)
- Comb操作,每个数值变量变化 例如 2 -> (2, 1)
- Reduce 操作
sum_count = rdd_pair.aggregateByKey(
(0 , 0),
lambda zero_tuple, values_: (zero_tuple[0] + values_, zero_tuple[1] + 1),
lambda tup0, tup1: (tup0[0] + tup1[0], tup0[1]+tup1[1]) # reduce
)
1.2 acombineByKey
- 源码
def combineByKey[C](
createCombiner: V => C,
mergeValue: (C, V) => C,
mergeCombiners: (C, C) => C): RDD[(K, C)] = self.withScope {
combineByKeyWithClassTag(createCombiner, mergeValue, mergeCombiners)(null)
}
1、createCombiner:V=>C 分组内的创建组合的函数。通俗点将就是对读进来的数据进行初始化,其把当前的值作为参数,可以对该值做一些转换操作,转换为我们想要的数据格式
2、mergeValue:(C,V)=>C 该函数主要是分区内的合并函数,作用在每一个分区内部。其功能主要是将V合并到之前(createCombiner)的元素C上 ,注意,这里的C指的是上一函数转换之后的数据格式,而这里的V指的是原始数据(上一函数为转换之前的)
3、mergeCombiners:(C,C)=>R 该函数主要是进行多分取合并,此时是将两个C合并为一个C,例如两个C:(Int)进行相加之后得到一个R:(Int)。相当于reduce(底层调用相同)。
combineByKey与reduceByKey的区别是:combineByKey可以返回与输入数据类型不一样的输出。
- 例子
sum_count1 = rdd_pair.combineByKey(
lambda values_: (values_, 1), # createCombiner
lambda combined, values_: (combined[0] + values_, combined[1] + 1), # 在combined中叠加
lambda values_, cnts: (values_[0] + cnts[0], values_[1]+cnts[1]) # reduce
)
1.3 foldByKey
sum_count2 = rdd_pair1.foldByKey(
(0, 0), # zero_value = (0, 0) = (sum, count)
lambda x, y : (x[0] + y[0], x[1] + y[1])
)
1.4 groupby
sum_count3 = rdd_pair.groupByKey().mapValues(lambda x : (sum(list(x)), len(list(x))))
# 或者分步减少计算
# sum_count3 = rdd_pair.groupByKey().mapValues(lambda x : list(x) )
# avg = sum_count3.map(lambda x : float(sum(x)) / float(len(x)))
1.5 reduceByKey
sum_count4 = rdd_pair1.reduceByKey(
lambda fs, nd: (fs[0] + nd[1], fs[0] + nd[1])
)