我想从tar-gzip文件(tgz)进行流式传输,其中包括我的实际CSV存储数据。
当我的数据以CSV文件形式出现时,我已经设法使用spark 2.2进行结构化流式处理,但实际上,数据是以gzip压缩的csv文件形式出现的。
结构化流式传输完成的触发器在处理CSV流之前是否有解压缩的方法?
我用来处理文件的代码是:
val schema = Encoders.product[RawData].schema
val trackerData = spark
.readStream
.option("delimiter", "\t")
.schema(schema)
.csv(path)
val exceptions = rawCientData
.as[String]
.flatMap(extractExceptions)
.as[ExceptionData]
当路径指向csv文件时,按预期生成输出。 但我想使用tar gzip文件。 当我尝试将这些文件放在给定路径时,我没有任何异常,批输出告诉我
"sources" : [ {
"description" : "FileStreamSource[file:/Users/matthias/spark/simple_spark/src/main/resources/zsessionlog*]",
"startOffset" : null,
"endOffset" : {
"logOffset" : 0
},
"numInputRows" : 1095,
"processedRowsPerSecond" : 211.0233185584891
} ],
但我没有处理任何实际数据。 控制台接收器如下所示:
+------+---+-----+
|window|id |count|
+------+---+-----+
+------+---+-----+
答案 0 :(得分:1)
我不认为在Spark中可以阅读tar.gz文件(有关一些想法,请参阅Read whole text files from a compression in Spark或gzip support in Spark)。
Spark确实支持gzip文件,但建议不要将它们拆分为单个分区(这反过来会使Spark几乎没有帮助)。
为了在Spark Structured Streaming中加载gzip压缩文件,您必须指定路径模式,以便文件包含在加载中,比如说zsessionlog*.csv.gz
或类似。否则,仅csv
仅加载CSV文件。
如果您坚持使用Spark Structured Streaming来处理tar.gz文件,您可以编写自定义流数据Source
来执行取消 - tar.gz
。
鉴于不建议将gzip文件作为Spark中的数据格式,使用Spark Structured Streaming的整个想法没有多大意义。
答案 1 :(得分:0)
我解决了以这种方式阅读.tar.gz(.tgz)文件的部分: 受此site的启发,我创建了自己的TGZ编解码器
final class DecompressTgzCodec extends CompressionCodec {
override def getDefaultExtension: String = ".tgz"
override def createOutputStream(out: OutputStream): CompressionOutputStream = ???
override def createOutputStream(out: OutputStream, compressor: Compressor): CompressionOutputStream = ???
override def createCompressor(): Compressor = ???
override def getCompressorType: Class[_ <: Compressor] = ???
override def createInputStream(in: InputStream): CompressionInputStream = {
new TarDecompressorStream(new TarArchiveInputStream(new GzipCompressorInputStream(in)))
}
override def createInputStream(in: InputStream, decompressor: Decompressor): CompressionInputStream = createInputStream(in)
override def createDecompressor(): Decompressor = null
override def getDecompressorType: Class[_ <: Decompressor] = null
final class TarDecompressorStream(in: TarArchiveInputStream) extends DecompressorStream(in) {
def updateStream(): Unit = {
// still have data in stream -> done
if (in.available() <= 0) {
// create stream content from following tar elements one by one
in.getNextTarEntry()
}
}
override def read: Int = {
checkStream()
updateStream()
in.read()
}
override def read(b: Array[Byte], off: Int, len: Int): Int = {
checkStream()
updateStream()
in.read(b, off, len)
}
override def resetState(): Unit = {}
}
}
并将其注册以供spark使用。
val conf = new SparkConf()
conf.set("spark.hadoop.io.compression.codecs", classOf[DecompressTgzCodec].getName)
val spark = SparkSession
.builder()
.master("local[*]")
.config(conf)
.appName("Streaming Example")
.getOrCreate()
完全像我希望的那样工作。