One minute
Spark RDD Shuffle internals
group-by is using an aggregator to combineValuesByKey
At the DAG level configuration:
See PairRDDFunctions.scala#L503-L505
val createCombiner = (v: V) => CompactBuffer(v)
val mergeValue = (buf: CompactBuffer[V], v: V) => buf += v
val mergeCombiners = (c1: CompactBuffer[V], c2: CompactBuffer[V]) => c1 ++= c2which eventually calls: PairRDDFunctions.combineByKeyWithClassTag
val aggregator = new Aggregator[K, V, C](
self.context.clean(createCombiner),
self.context.clean(mergeValue),
self.context.clean(mergeCombiners))which in turn, boils down to:
new ShuffledRDD[K, V, C](self, partitioner)
.setSerializer(serializer)
.setAggregator(aggregator)
.setMapSideCombine(mapSideCombine)Reduce side
On the reduce side, when the DAG is actually materialized:
ShuffledRDD#compute is the actual RDD implm for a shuffled RDD.
This in turn uses BlockStoreShuffleReader#read which has the following important points:
- Read the shuffle blocks from mappers (network via Netty or local):
ShuffleBlockFetcherIterator - Deserialize:
recordIter Aggregate the (K,V)s by key:
aggregatedIteraggregator#combineValuesByKeyval combiners = new ExternalAppendOnlyMap[K, V, C] (createCombiner, mergeValue, mergeCombiners)ExternalAppendOnlyMap will accumulate in memory the (K,agg(V)) till spill limit is hit, then spills (keep a reference to an on-disk partial sorted iterator)
The final
resultIteris actually provided byExternalSorterwhich wraps theaggregatedIterand does the final merge sort of partial sorted results. SeeExternalSorter#merge
ForgroupBytheaggregator.isDefined=false, onlyordering.isDefined=true
References:
[1] ExternalAppendOnlyMap: https://github.com/JerryLead/SparkInternals/blob/master/markdown/english/4-shuffleDetails.md#externalappendonlymap
repartitionAndSortWithPartition is ligher(?)
195 Words
2019-05-24 23:45 +0300