我正在使用AWS,我有使用Spark和Hive的工作流程。我的数据按日期分区,所以每天我在S3存储中都有一个新分区。 我的问题是有一天加载数据失败并且我必须重新执行该分区。写下的代码是下一个:
df // My data in a Dataframe
.write
.format(getFormat(target)) // csv by default, but could be parquet, ORC...
.mode(getSaveMode("overwrite")) // Append by default, but in future it should be Overwrite
.partitionBy(partitionName) // Column of the partition, the date
.options(target.options) // header, separator...
.option("path", target.path) // the path where it will be storage
.saveAsTable(target.tableName) // the table name
我的流程会发生什么?如果我使用SaveMode.Overwrite,整个表将被删除,我将只保存分区。如果我使用SaveMode.Append我可能有重复的数据。
进行搜索,我发现Hive支持这种覆盖,只有分区,但是使用hql语句,我没有。
我们需要在Hive上使用解决方案,因此我们无法使用此alternative option(直接转到csv)。
我发现这个Jira ticket假设要解决我遇到的问题,但是尝试使用最新版本的Spark(2.3.0),情况是一样的。它删除整个表并保存分区,而不是覆盖我的数据所具有的分区。
试图让这一点更清楚,这是一个例子:
由A
分区数据:
| A | B | C |
|---|---|---|
| b | 1 | 2 |
| c | 1 | 2 |
表:
| A | B | C |
|---|---|---|
| a | 1 | 2 |
| b | 5 | 2 |
我想要的是:在表格中,分区a
保留在表格中,分区b
覆盖数据,并添加分区c
。有没有使用Spark的解决方案,我能做到这一点?
我的最后一个选项是首先删除要保存的分区,然后使用SaveMode.Append,但如果没有其他解决方案,我会尝试这个。
答案 0 :(得分:10)
如果您使用的是Spark 2.3.0,请尝试将FirstName
设置为spark.sql.sources.partitionOverwriteMode
,需要对数据集进行分区,并覆盖写入模式。
dynamic
答案 1 :(得分:1)
我建议使用sparksession运行sql。您可以通过从现有数据集中选择列来运行“插入覆盖分区查询”。这个解决方案肯定会覆盖分区。
答案 2 :(得分:1)
因此,如果您使用的是Spark版本<2.3,并且想要动态写入分区而不删除其他分区,则可以实施以下解决方案。
想法是将数据集注册为表,然后使用spark.sql()运行INSERT查询。
// Create SparkSession with Hive dynamic partitioning enabled
val spark: SparkSession =
SparkSession
.builder()
.appName("StatsAnalyzer")
.enableHiveSupport()
.config("hive.exec.dynamic.partition", "true")
.config("hive.exec.dynamic.partition.mode", "nonstrict")
.getOrCreate()
// Register the dataframe as a Hive table
impressionsDF.createOrReplaceTempView("impressions_dataframe")
// Create the output Hive table
spark.sql(
s"""
|CREATE EXTERNAL TABLE stats (
| ad STRING,
| impressions INT,
| clicks INT
|) PARTITIONED BY (country STRING, year INT, month INT, day INT)
|ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n'
""".stripMargin
)
// Write the data into disk as Hive partitions
spark.sql(
s"""
|INSERT OVERWRITE TABLE stats
|PARTITION(country = 'US', year = 2017, month = 3, day)
|SELECT ad, SUM(impressions), SUM(clicks), day
|FROM impressions_dataframe
|GROUP BY ad
""".stripMargin
)
答案 3 :(得分:0)
在wandermonk @提到的内容中添加
动态分区插入仅在SQL模式下受支持(对于INSERT OVERWRITE TABLE SQL语句)。非基于文件的数据源(即InsertableRelations)不支持动态分区插入。
对于“动态分区插入”,OVERWRITE关键字的行为由spark.sql.sources.partitionOverwriteMode配置属性控制(默认值:静态)。该属性控制Spark是应该删除与分区规范匹配的所有分区,而不管是否有要写入的数据(静态),还是仅删除将要写入数据的那些分区(动态)。
启用动态覆盖模式后,Spark将仅删除要写入其数据的分区。其他所有分区均保持不变。
来自
从使用Spark(https://medium.com/a-muggles-pensieve/writing-into-dynamic-partitions-using-spark-2e2b818a007a)写入动态分区
Spark现在可以像Hive一样写分区的数据。这意味着只有被INSERT查询触摸的分区才被覆盖,而其他分区则不被触摸。