DataFrame
を使用してDataFrameWriter
をParquet形式でHDFSに保存しようとしていますが、次のように3つの列値で分割されています。
dataFrame.write.mode(SaveMode.Overwrite).partitionBy("eventdate", "hour", "processtime").parquet(path)
この質問 で述べたように、partitionBy
はpath
にあるパーティションの既存の完全な階層を削除し、dataFrame
のパーティションに置き換えます。特定の日の新しい増分データが定期的に入ってくるので、私が望むのは、dataFrame
がデータを持っている階層内のパーティションのみを置き換え、他のパーティションはそのままにしておきます。
これを行うには、次のようなフルパスを使用して各パーティションを個別に保存する必要があります:
singlePartition.write.mode(SaveMode.Overwrite).parquet(path + "/eventdate=2017-01-01/hour=0/processtime=1234567890")
しかし、フルパスを使用してデータを書き出すことができるように、データを単一パーティションDataFrame
sに整理する最良の方法を理解するのに苦労しています。一つのアイデアは次のようなものでした:
dataFrame.repartition("eventdate", "hour", "processtime").foreachPartition ...
ただし、foreachPartition
はIterator[Row]
これは、Parquet形式への書き込みには理想的ではありません。
また、select...distinct eventdate, hour, processtime
パーティションのリストを取得し、それらのパーティションごとに元のデータフレームをフィルタリングし、その結果を完全なパーティションパスに保存します。ただし、個別のクエリと各パーティションのフィルターは、多くのフィルター/書き込み操作になるため、あまり効率的ではありません。
dataFrame
にデータがない既存のパーティションを保存するよりクリーンな方法があることを望んでいますか?
読んでくれてありがとう。
Sparkバージョン:2.1
モードオプションAppend
にはキャッチがあります!
df.write.partitionBy("y","m","d")
.mode(SaveMode.Append)
.parquet("/data/Hive/warehouse/mydbname.db/" + tableName)
私はテストして、これが既存のパーティションファイルを保持することを確認しました。ただし、今回の問題は次のとおりです。同じコードを2回(同じデータで)実行すると、同じデータの既存のパーケットファイルを置き換えるのではなく、新しいパーケットファイルを作成します(Spark 1.6)。したがって、Append
を使用する代わりに、Overwrite
を使用してこの問題を解決できます。テーブルレベルで上書きする代わりに、パーティションレベルで上書きする必要があります。
df.write.mode(SaveMode.Overwrite)
.parquet("/data/Hive/warehouse/mydbname.db/" + tableName + "/y=" + year + "/m=" + month + "/d=" + day)
詳細については、次のリンクを参照してください。
spark dataframe write method で特定のパーティションを上書きする
(スリヤントのコメントの後、返信を更新しました。Thnx。)
これは非常に古いことを知っています。投稿されたソリューションが表示されないため、先に投稿します。このアプローチは、書き込み先のディレクトリにHiveテーブルがあることを前提としています。この問題に対処する1つの方法は、dataFrame
から一時ビューを作成し、それをテーブルに追加してから、通常のHiveのようなinsert overwrite table ...
コマンド:
dataFrame.createOrReplaceTempView("temp_view")
spark.sql("insert overwrite table table_name partition ('eventdate', 'hour', 'processtime')select * from temp_view")
古いパーティションを保持しながら、新しいパーティションにのみ(上書き)書き込みます。
これは古いトピックですが、私は同じ問題を抱えていて、別の解決策を見つけました。次のコマンドを使用して、パーティションの上書きモードを動的に設定するだけです。
spark.conf.set('spark.sql.sources.partitionOverwriteMode', 'dynamic')
したがって、私のsparkセッションは次のように構成されます。
spark = SparkSession.builder.appName('AppName').getOrCreate()
spark.conf.set('spark.sql.sources.partitionOverwriteMode', 'dynamic')