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的核心原理。后面抽空继续学习。

 

posted on 2022-09-04 17:00  淡墨痕  阅读(372)  评论(0)    收藏  举报