web-dev-qa-db-ja.com

sparkを使用して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でのソリューションが必要なので、これは使用できません 代替オプション (csvに直接)。

私はこれを見つけました Jiraチケット 私が持っている問題を解決することを想定していますが、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を使用することですが、他の解決策がない場合はこれを試します。

10
H. M.

Spark 2.3.0を使用している場合は、spark.sql.sources.partitionOverwriteModedynamicに設定すると、データセットをパーティション分割して、書き込みモードで上書きする必要があります。

spark.conf.set("spark.sql.sources.partitionOverwriteMode","dynamic")
data.write.mode("overwrite").insertInto("partitioned_table")
11
wandermonk

私はsparksessionを使用してSQLを実行することをお勧めします。既存のデータセットから列を選択することにより、「上書きパーティションクエリの挿入」を実行できます。このソリューションは確かにパーティションのみを上書きします。

1
Sourav Gulati

したがって、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
)
0
ravi malhotra