如何删除Spark结构化流创建的旧数据?

时间:2020-03-20 11:40:45

标签: apache-spark apache-spark-sql spark-structured-streaming apache-spark-2.0

如何删除Spark结构化流(Spark 2.4.5)创建的旧数据?

我有实木复合地板/ avro格式(非增量)上的HDFS数据,它是由 Spark Structured Streaming 创建的,并按时间(年份的年,月,日)进行了分区月,小时)。

数据创建如下:

cdo -setattribute,Band1@_FillValue=-1.0 infile.nc outfile.nc

结果,我的分区文件夹布局如下:

query = df.writeStream.format("avro").partitionBy("year", "month", "day", "hour").outputMode("append").option("checkpointLocation", "/data/avro.cp").start("/data/avro")

如何删除旧数据,例如早于year = 2020,month = 2,day = 13,hour = 14的旧数据?

只需删除相关文件夹

./year=2020/month=3/day=13/hour=12
./year=2020/month=3/day=13/hour=13
./year=2020/month=3/day=13/hour=14
./year=2020/month=3/day=13/hour=15
./year=2020/month=3/day=13/hour=16

从文件系统读取批处理数据帧时引发异常:

./year=2020/month=3/day=13/hour=12
./year=2020/month=3/day=13/hour=13

我已经发现这与检查点使用的df = spark.read.format("avro").load("/data/avro") java.io.FileNotFoundException: File file:/data/avro/year=2020/month=3/day=13/hour=12/part-00000-0cc84e65-3f49-4686-85e3-1ecf48952794.c000.avro does not exist 文件夹有关。

感谢您的帮助。

4 个答案:

答案 0 :(得分:3)

似乎我找到了解决方案/解决方法。 关键概念是使用FileStreamSinkLog,然后将SinkFileStatus加上其操作设置为delete

  1. 加载FileStreamSinkLog

    sinkLog = new FileStreamSinkLog(1, spark, full-path-to-spark-metadata-dir);
    
  2. 获取最新的SinkFileStatus

    Option<Tuple2<Object, SinkFileStatus[]>> latest = sinkLog.getLatest();
    long batchId = (long)latest.get()._1;
    SinkFileStatus[] fileStatuses = latest.get()._2;
    
  3. 删除旧文件

  4. 通过delete动作向fileStatuses数组添加新条目

  5. 使用更新后的batchId

  6. 回写fileStatuses日志文件

答案 1 :(得分:1)

您不能删除该文件夹,除非您也删除了它对应的检查点文件夹。您试图在检查点仍然了解该文件夹的同时删除该文件夹,因此这就是发生错误的原因。

但是,除非有必要,否则我真的不建议您将检查点文件夹弄乱。如果您有可能,我建议您将旧数据移至其他数据存储类型,例如AWS Standard-> Glacier。

答案 2 :(得分:0)

为了便于复制/粘贴,这里有一个从 spark 3.0.1 开始的工作代码 (scala) 片段。删除一个文件并写入一个新批次:

import org.apache.spark.sql.execution.streaming.FileStreamSinkLog

import scala.language.postfixOps
import scala.sys.process._
import scala.util.Try

        val sinkLog = new FileStreamSinkLog (
            1,
            spark,
            SPARK_METADATA_ROOT
        )
        val head = sinkLog.allFiles().head

        val deleteCommand = s"hadoop fs -rm ${head.path}"
        println (Try (deleteCommand ! processlogger).getOrElse(s""""$deleteCommand" failed""") )

        head.copy(action = FileStreamSinkLog.DELETE_ACTION)

        sinkLog
            .add (
                latestBatch.get._1+1,
                Array(head.copy(action = FileStreamSinkLog.DELETE_ACTION))
                )

答案 3 :(得分:0)

对于 Spark 3.0.0 及以上版本,已实现。

基本上它为已提交的文件添加了 3 个策略(ARCHIVE、DELETE、OFF)并允许对其进行配置。

老实说,我自己从未尝试过,但我在这里看到了一些关于 Spark 3+ 的答案,绝对值得一提。