今天在练习Spark代码的时候遇到一个奇怪的现象:
这是我的原始数据,在idea中创建一个txt文件:
这是我的代码:
val rdd: RDD[String] = sc.textFile("input/test.txt", 3) // 设置分区数为3
rdd.saveAsTextFile("output")
结果出现了四个分区:
要想解决这个问题,首先应该明确两个点:
- 分区数量到底是多少?
- 每个分区到底存储什么数据?
遇事不决查看源码。点开textFile方法的源码:
在代码的最后一行,我看到了hadoopFile、TextInputFormat。因此可以基本断定,Spark读取文件的方式就是Hadoop读取文件的方式。
Hadoop在计算分区大小时,需要知道:文件总大小totalSize和每个分区应该读的字节大小goalSize = totalSize / 传入的分区数。当goalSize不为整数时,还需要判断是否超过SPLIT_SLOP (1.1)。以便决定是否创建新的分区。
因此我首先判断文件的总大小。使用NotePad++工具打开:
让我没想到的是一共有7个字符!
紧接着计算分区数:7 / 3 = 2余1。1/2大于2*0.1。因此还需要创建一个分区,因此应该是四个分区才对。
这样,第一个问题就解决了,分区数应该是4个。
那么每个分区到底存多少个数据呢?
根据Hadoop默认的读取数据的原则,以偏移量为基准按行读取。因此每个分区文件应该读goalSize = 7 / 3 = 2,每个文件读两个字节。但由于Hadoop按行读取的原则,因此不论goalSize是多少,每次都要读取一行。文字演示:
为了验证上述的结论,我重新设置了一组数据:
仍然设置分区数为3:
val rdd: RDD[String] = sc.textFile("input/test.txt", 3)
rdd.saveAsTextFile("output")
分区数为4,我按照上述思路进行分析:
感兴趣的同学可以自行验证一下。