一般来说,saveAsTextFile是根据执行task的数量生成相应个数的结果文件,例如part-00000一直到part-0000n,n是task的个数,也是最后stage的分区数。
要使最后的结果只生成一个文件,可以调用coalesce(1,true)或reparation(1)。
repartition(numPartitions:Int):RDD[T]
coalesce(numPartitions:Int,shuffle:Boolean=false):RDD[T]
其中,reparation是coalesce接口中shuffle为true的实现。
RDD中调用coalesce(1,true).saveAsTextFile(),即在做完计算后将数据汇集到一个分区,然后再执行保存。显然,对于一个分区spark自然只起一个task来执行保存的动作,最后也只有一个文件产生。
以上操作时将分布在各个节点上的RDD partition合并到单一主机后再保存到磁盘(HDFS)上。
代价是,由于spark是实时并行处理大批量数据,若强行要求最后只有一个分区,必然导致大量的磁盘IO和网络IO产生,并且最终执行reduce操作节点的内存也很可能溢出。Spark程序可能运行缓慢挂掉。
对于分布式计算,我们需要改变原来的单节点单线程的思维,对程序的理解要转变为多节点多进程,熟悉多节点集群自然产生多个文件这种模式。
对于最后HDFS上生成的多个文件(如/hdfs/result),可手动执行命令合并为一个本地文件(如/data/test.log):
hadoop fs -cat /hdfs/result/part-* > /data/test.log
或
hadoop fs -getmerge /hdfs/result /data/test.log