镶木地板Pyspark中的UPSERT

时间:2020-01-26 20:04:57

标签: amazon-s3 pyspark etl parquet

我在s3中有实木复合地板文件,具有以下分区: 年/月/日/ some_id 我想使用Spark(PySpark)在过去的 14天中每天进行一次UPSERT-我想替换s3中的现有数据(每个分区一个镶木文件),但不想删除14天之前的日子.. 我尝试了两种保存模式: 追加-不好,因为它只是添加了另一个文件。 覆盖-正在删除过去的数据和其他分区的数据。

有什么方法或最佳实践可以克服吗?我应该在每次运行中从s3中读取所有数据,然后再次写回吗?也许重命名文件以便 append 替换s3中的当前文件?

非常感谢!

3 个答案:

答案 0 :(得分:4)

我通常会做类似的事情。以我为例,我进行了ETL并将一天的数据附加到 parquet 文件中:

关键是要处理要写入的数据(在我的情况下为实际日期),请确保按date列进行分区,并覆盖当前日期的所有数据>。

这将保留所有旧数据。例如:

(
    sdf
    .write
    .format("parquet")
    .mode("overwrite")
    .partitionBy("date")
    .option("replaceWhere", "2020-01-27")
    .save(uri)
)

您还可以查看delta.io,它是镶木地板格式的扩展,提供了一些有趣的功能,例如 ACID 交易。

答案 1 :(得分:1)

据我所知,S3没有更新操作。一旦将对象添加到s3,就无法修改。 (您必须替换另一个对象或附加文件)

无论如何,您都必须读取所有数据,您可以指定要读取的时间轴,分区修剪有助于仅读取时间轴内的分区。

答案 2 :(得分:1)

感谢所有有用的解决方案。 我最终使用了适合我的用例的一些配置-在编写镶木地板时使用 overwrite 模式以及以下配置:

我添加了此配置:

spark.conf.set("spark.sql.sources.partitionOverwriteMode", "dynamic")
使用此配置的

spark将仅覆盖要写入其数据的分区。所有其他(过去)分区均保持不变-参见此处:

https://jaceklaskowski.gitbooks.io/mastering-spark-sql/spark-sql-dynamic-partition-inserts.html