Scala 如何在ApacheSpark中读取包含多个文件的zip文件
我有一个压缩文件包含多个文本文件。 我想读取每个文件并构建一个包含每个文件内容的RDD列表Scala 如何在ApacheSpark中读取包含多个文件的zip文件,scala,apache-spark,pyspark,Scala,Apache Spark,Pyspark,我有一个压缩文件包含多个文本文件。 我想读取每个文件并构建一个包含每个文件内容的RDD列表 val test = sc.textFile("/Volumes/work/data/kaggle/dato/test/5.zip") 将只显示整个文件,但如何迭代zip的每个内容,然后使用Spark将其保存在RDD中 我对Scala或Python很在行 使用Spark在Python中可能的解决方案- archive = zipfile.ZipFile(archive_path, 'r') file_p
val test = sc.textFile("/Volumes/work/data/kaggle/dato/test/5.zip")
将只显示整个文件,但如何迭代zip的每个内容,然后使用Spark将其保存在RDD中
我对Scala或Python很在行
使用Spark在Python中可能的解决方案-
archive = zipfile.ZipFile(archive_path, 'r')
file_paths = zipfile.ZipFile.namelist(archive)
for file_path in file_paths:
urls = file_path.split("/")
urlId = urls[-1].split('_')[0]
如果您正在读取二进制文件,请使用
sc.binaryFiles
。这将返回一个包含文件名的元组RDD和一个PortableDataStream
。您可以将后者输入到ApacheSpark默认压缩支持中
我已经在其他答案中写下了所有必要的理论,您可能想参考:
读取包含多个文件的zip文件
我遵循了ZipInputStream提供的建议并使用了ZipInputStream
。这给了我这个解决方案,它返回zip内容的RDD[String]
import java.io.{BufferedReader, InputStreamReader}
import java.util.zip.ZipInputStream
import org.apache.spark.SparkContext
import org.apache.spark.input.PortableDataStream
import org.apache.spark.rdd.RDD
implicit class ZipSparkContext(val sc: SparkContext) extends AnyVal {
def readFile(path: String,
minPartitions: Int = sc.defaultMinPartitions): RDD[String] = {
if (path.endsWith(".zip")) {
sc.binaryFiles(path, minPartitions)
.flatMap { case (name: String, content: PortableDataStream) =>
val zis = new ZipInputStream(content.open)
Stream.continually(zis.getNextEntry)
.takeWhile {
case null => zis.close(); false
case _ => true
}
.flatMap { _ =>
val br = new BufferedReader(new InputStreamReader(zis))
Stream.continually(br.readLine()).takeWhile(_ != null)
}
}
} else {
sc.textFile(path, minPartitions)
}
}
}
只需导入隐式类并在SparkContext上调用readFile方法即可使用它:
import com.github.atais.spark.Implicits.ZipSparkContext
sc.readFile(path)
以下是@Atais解决方案的工作版本(需要通过关闭流来增强): 然后,您只需执行以下操作即可读取zip文件:
sc.readFile(path)
这只过滤第一行。有人能分享你的见解吗。我正在尝试读取一个压缩的CSV文件,并创建JavaRDD进行进一步处理
JavaPairRDD<String, PortableDataStream> zipData =
sc.binaryFiles("hdfs://temp.zip");
JavaRDD<Record> newRDDRecord = zipData.flatMap(
new FlatMapFunction<Tuple2<String, PortableDataStream>, Record>(){
public Iterator<Record> call(Tuple2<String,PortableDataStream> content) throws Exception {
List<Record> records = new ArrayList<Record>();
ZipInputStream zin = new ZipInputStream(content._2.open());
ZipEntry zipEntry;
while ((zipEntry = zin.getNextEntry()) != null) {
count++;
if (!zipEntry.isDirectory()) {
Record sd;
String line;
InputStreamReader streamReader = new InputStreamReader(zin);
BufferedReader bufferedReader = new BufferedReader(streamReader);
line = bufferedReader.readLine();
String[] records= new CSVParser().parseLineMulti(line);
sd = new Record(TimeBuilder.convertStringToTimestamp(records[0]),
getDefaultValue(records[1]),
getDefaultValue(records[22]));
records.add(sd);
}
}
return records.iterator();
}
});
javapairdd-zipData=
sc.binaryFiles(“hdfs://temp.zip");
JavaRDD newRDDRecord=zipData.flatMap(
新FlatMapFunction(){
公共迭代器调用(Tuple2内容)引发异常{
列表记录=新的ArrayList();
ZipInputStream zin=新的ZipInputStream(content._2.open());
齐彭特里;
while((zipEntry=zin.getnextery())!=null){
计数++;
如果(!zipEntry.isDirectory()){
记录sd;
弦线;
InputStreamReader streamReader=新的InputStreamReader(zin);
BufferedReader BufferedReader=新的BufferedReader(streamReader);
line=bufferedReader.readLine();
String[]records=new CSVParser().parseLineMulti(行);
sd=新记录(TimeBuilder.convertStringToTimestamp(记录[0]),
getDefaultValue(记录[1]),
getDefaultValue(记录[22]);
记录.增补(sd);
}
}
返回记录。迭代器();
}
});
这里是另一个可行的解决方案,它给出了文件名,以后可以将文件名拆分并用于从中创建单独的模式
隐式类ZipSparkContext(val sc:SparkContext)扩展了AnyVal{
def readFile(路径:字符串,
minPartitions:Int=sc.defaultMinPartitions):RDD[String]={
if(path.toLowerCase.contains(“zip”)){
sc.binaryFiles(路径、分区)
.平面图{
案例(zipFilePath,zipContent)⇒
val zipInputStream=新的zipInputStream(zipContent.open())
Stream.continuous(zipInputStream.getnextry)
.takeWhile(!=null)
.map{x⇒
val filename1=x.getName
scala.io.Source.fromInputStream(zipInputStream,“UTF-8”).getLines.mkString(s“~${filename1}\n”)+s“~${filename1}”
}#::{zipInputStream.close;Stream.empty[String]}
}
}否则{
sc.textFile(路径、分区)
}
}
}
您没有关闭连接。@程序员我试图关闭连接,但此方法失败。所以我把它留给了Spark。@Atais Spark在我的情况下没有关闭溪流。我试图从S3中读取数千个文件,但由于连接线程池耗尽而失败,但一旦我关闭代码中的流,它就工作了。无论如何,及时清理总是一个好主意。你能想出一个答案吗?你是如何处理的?或者把它贴在什么地方?我还有其他问题。将张贴一旦完成。这是一个类似于Hi@AbhishekChoudhary的问题——下面哪种解决方案最适合你?谢谢。使用spark APi读取保存在单个RDD中的所有文件,然后使用不同的过滤机制对数据进行分区解压缩文件本质上是一个单线程过程——在spark中这样做不是浪费资源吗?是的,但是现在在Spark中也有API来读取压缩文件。如何将文件名添加到输出中,以便根据文件名进行过滤想象一个zip文件有多个模式文件我可以在文件名上使用Spark input_file_name虚拟列,如果我能在rdd@mahmoud mehdithis中获得文件名,它也会给出文件名,.map{x⇒ val filename1=x.getName scala.io.Source.fromInputStream(zipInputStream,“UTF-8”).getLines.mkString(s“~${filename1}\n”)+s“~${filename1}”}#:{zipInputStream.close;Stream.empty[String]}
JavaPairRDD<String, PortableDataStream> zipData =
sc.binaryFiles("hdfs://temp.zip");
JavaRDD<Record> newRDDRecord = zipData.flatMap(
new FlatMapFunction<Tuple2<String, PortableDataStream>, Record>(){
public Iterator<Record> call(Tuple2<String,PortableDataStream> content) throws Exception {
List<Record> records = new ArrayList<Record>();
ZipInputStream zin = new ZipInputStream(content._2.open());
ZipEntry zipEntry;
while ((zipEntry = zin.getNextEntry()) != null) {
count++;
if (!zipEntry.isDirectory()) {
Record sd;
String line;
InputStreamReader streamReader = new InputStreamReader(zin);
BufferedReader bufferedReader = new BufferedReader(streamReader);
line = bufferedReader.readLine();
String[] records= new CSVParser().parseLineMulti(line);
sd = new Record(TimeBuilder.convertStringToTimestamp(records[0]),
getDefaultValue(records[1]),
getDefaultValue(records[22]));
records.add(sd);
}
}
return records.iterator();
}
});