我要逐一查看HDFS上的文件列表,将其作为文本打开,然后保存回HDFS,到另一个位置。正在解析数据,然后合并 part 文件并将其保存为原始名称,后缀为BZIP2。但是,它相当慢-每个文件大约需要3s,而每个文件夹有10,000多个。我不确定如何保存文件名信息,因此需要逐个文件查找。我需要名称才能执行MD5,并“确认”没有发生任何信息丢失。
这是我的代码:
import org.apache.hadoop.fs.{FileSystem, Path, FileUtil}
import org.apache.spark.deploy.SparkHadoopUtil
import org.apache.spark.sql._
import org.apache.spark.sql.functions._
import org.apache.spark.sql.functions.broadcast
import org.apache.spark.sql.types._
import org.apache.spark.{SparkConf, SparkContext}
sc.getConf.set("spark.hadoop.mapred.output.compress", "true")
sc.getConf.set("spark.hadoop.mapred.output.compression.codec", "true")
sc.getConf.set("spark.hadoop.mapred.output.compression.codec",
"org.apache.hadoop.io.compress.BZip2Codec")
sc.getConf.set("spark.hadoop.mapred.output.compression.type", "BLOCK")
val hdfsConf = SparkHadoopUtil.get.newConfiguration(sc.getConf)
val hdfs = FileSystem.get(hdfsConf)
val sourcePath = new Path("/source/*20180801*")
hdfs.globStatus(sourcePath).foreach( fileStatus => {
val fileName = fileStatus.getPath().getName()
val filePathName = fileStatus.getPath().toString
if (fileName.contains(".done")) {
/* open, then save compressed */
val myFile = sc.textFile(filePathName)
val compressedBasePath = "/destination/compressed/"
/* use tmp_ to store folder w/ parts in it */
val compressedPath = compressedBasePath + "tmp_/" + fileName
myFile.saveAsTextFile(compressedPath,
classOf[org.apache.hadoop.io.compress.BZip2Codec])
/* merge part* -> old_name.bzip */
FileUtil.copyMerge(hdfs, new Path(compressedPath), hdfs,
new Path(compressedBasePath + "/" + fileName + ".bzip2"),
true, hdfsConf, null)
myFile.unpersist()
}
})
在我需要测试之前,我使用了类似的方法:
val myFile = sc.textFile("/source/*20180801*")
myFile.saveAsTextFile(compressedPath,
classOf[org.apache.hadoop.io.compress.BZip2Codec])
但是我不能重命名,所以我需要名称。 有什么想法我可以做什么?
更新:
多亏了注释中的建议和this particular question,我得以使用并行集合解决此问题。唯一真正的更改是导入import scala.collection.parallel.immutable.ParVector
并添加par
方法调用,然后再进行foreach
。
有关并行集合的完整文章:https://docs.scala-lang.org/overviews/parallel-collections/overview.html
Thx
答案 0 :(得分:0)
原始问题的评论中有两种可能的解决方案:
TBH,我只测试了第二种方法,因为它是一种更快的方法(警告更少)。最终解决方案只需要进行最小的更改-返回适当的lib导入和Array hdfs.globStatus(sourcePath)
调用的并行化。这是最终的代码,其中删除了注释,并添加了两个注释,以便于发现更改。
import org.apache.hadoop.fs.{FileSystem, Path, FileUtil}
import org.apache.spark.deploy.SparkHadoopUtil
import org.apache.spark.sql._
import org.apache.spark.sql.functions._
import org.apache.spark.sql.functions.broadcast
import org.apache.spark.sql.types._
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.parallel.immutable.ParVector /* added */
sc.getConf.set("spark.hadoop.mapred.output.compress", "true")
sc.getConf.set("spark.hadoop.mapred.output.compression.codec", "true")
sc.getConf.set("spark.hadoop.mapred.output.compression.codec",
"org.apache.hadoop.io.compress.BZip2Codec")
sc.getConf.set("spark.hadoop.mapred.output.compression.type", "BLOCK")
val hdfsConf = SparkHadoopUtil.get.newConfiguration(sc.getConf)
val hdfs = FileSystem.get(hdfsConf)
val sourcePath = new Path("/source/*20180801*")
/* note the par method call below */
hdfs.globStatus(sourcePath).par.foreach( fileStatus => {
val fileName = fileStatus.getPath().getName()
val filePathName = fileStatus.getPath().toString
if (fileName.contains(".done")) {
val myFile = sc.textFile(filePathName)
val compressedBasePath = "/destination/compressed/"
val compressedPath = compressedBasePath + "tmp_/" + fileName
myFile.saveAsTextFile(compressedPath,
classOf[org.apache.hadoop.io.compress.BZip2Codec])
FileUtil.copyMerge(hdfs, new Path(compressedPath), hdfs,
new Path(compressedBasePath + "/" +
fileName.replace(".done", ".done.bz2")),
true, hdfsConf, null)
myFile.unpersist()
}
})