Spark记录(五):Dataset.count()方法源码剖析-下篇
书接上回(https://www.cnblogs.com/zzq6032010/p/16323297.html)
Dataset.count()方法为:
1 def count(): Long = withAction("count", groupBy().count().queryExecution) { plan => 2 plan.executeCollect().head.getLong(0) 3 }
上一次已经将第一行追踪完毕:主要是用于生成执行计划以及设置上下文信息。这次继续追踪第二行函数体,看看Spark是如何将Dataset这个分布式数据集的大小给统计出来的。
executeCollect方法如下所示:
1 def executeCollect(): Array[InternalRow] = { 2 val byteArrayRdd = getByteArrayRdd() 3 4 val results = ArrayBuffer[InternalRow]() 5 byteArrayRdd.collect().foreach { countAndBytes => 6 decodeUnsafeRows(countAndBytes._2).foreach(results.+=) 7 } 8 results.toArray 9 }
其中:
1、getByteArrayRdd方法通过调用mapPartitionsInternal方法将各分区种的数据转换成RDD[(Long, Array[Byte])],其中元组的第一个元素是分区中的数据行数。
2、byteArrayRdd.collect()方法将所有分区数据以数组的形式汇集到driver端,数组中元素的数据类型即RDD[(Long, Array[Byte])]。
3、foreach方法里面,将元组中第二个元素解码,从Array[Byte]转换成InternalRow(实际是子类UnsafeRow),然后逐个添加到results中。
由上一篇文章可知,执行计划执行的是count(1)聚合函数,故返回的数组里面,实际只有1条数据,且里面有总条数。所以执行完executeCollect之后就是.head和.getLong,以此获取到Dataset中的总条数,至此count结束。
其实继续详细深究的话,这中间还有很多疑问:比如count(1)函数是怎么传到executor的?是解析成什么实际函数执行的?其中会涉及到Spark的核心原理。后面抽空继续学习。
浙公网安备 33010602011771号