spark reduceByKey原始碼解析

鴨梨山大哎發表於2020-12-06

使用關聯和可交換的歸約函式合併每個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)
    }
  }

相關文章