使用spark覆盖hive分区

时间:2018-04-23 09:02:54

标签: scala amazon-web-services apache-spark hadoop hive

我正在使用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,但如果没有其他解决方案,我会尝试这个。

4 个答案:

答案 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查询触摸的分区才被覆盖,而其他分区则不被触摸。