使用关联和可交换的归约函数合并每个key的value。 在将结果发送给reducer之前,这还将在每个Mapper上本地执行合并,类似于MapReduce中的“ combiner”。
def reduceByKey(partitioner: Partitioner, func: (V, V) => V): RDD[(K, V)] = self.withScope {
combineByKeyWithClassTag[V]((v: V) => v, func, func, partitioner)
}
调用了combineByKeyWithClassTag
,继续查看
::实验::通用函数,使用一组自定义的聚合函数来组合每个键的元素。
对于“组合类型” C,将RDD [(K,V)]转换为RDD [(K,C)]类型的结果
用户提供三个功能:
createCombiner,它将V变成C(例如,创建一个元素列表)
mergeValue,将V合并为C(例如,将其添加到列表的末尾)
mergeCombiners,将两个C合并为一个。
此外,用户可以控制输出RDD的分区,以及是否执行map侧聚合(如果一个映射器可以使用相同的键产生多个项目)。
注意:
V和C可以不同-例如,可以将类型(Int,Int)的RDD分组为类型(Int,Seq [Int])的RDD。
def combineByKeyWithClassTag[C](
createCombiner: V => C,
mergeValue: (C, V) => C,
mergeCombiners: (C, C) => C,
partitioner: Partitioner,
mapSideCombine: Boolean = true,
serializer: Serializer = null)(implicit ct: ClassTag[C]): RDD[(K, C)] = self.withScope {
require(mergeCombiners != null, "mergeCombiners must be defined") // required as of Spark 0.9.0
if (keyClass.isArray) {
if (mapSideCombine) {
throw new SparkException("Cannot use map-side combining with array keys.")
}
if (partitioner.isInstanceOf[HashPartitioner]) {
throw new SparkException("HashPartitioner cannot partition array keys.")
}
}
val aggregator = new Aggregator[K, V, C](
self.context.clean(createCombiner),
self.context.clean(mergeValue),
self.context.clean(mergeCombiners))
if (self.partitioner == Some(partitioner)) {
self.mapPartitions(iter => {
val context = TaskContext.get()
new InterruptibleIterator(context, aggregator.combineValuesByKey(iter, context))
}, preservesPartitioning = true)
} else {
new ShuffledRDD[K, V, C](self, partitioner)
.setSerializer(serializer)
.setAggregator(aggregator)
.setMapSideCombine(mapSideCombine)
}
}