私は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を使用することですが、他の解決策がない場合はこれを試します。
Spark 2.3.0を使用している場合は、spark.sql.sources.partitionOverwriteMode
をdynamic
に設定すると、データセットをパーティション分割して、書き込みモードで上書きする必要があります。
spark.conf.set("spark.sql.sources.partitionOverwriteMode","dynamic")
data.write.mode("overwrite").insertInto("partitioned_table")
私はsparksessionを使用してSQLを実行することをお勧めします。既存のデータセットから列を選択することにより、「上書きパーティションクエリの挿入」を実行できます。このソリューションは確かにパーティションのみを上書きします。
したがって、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
)