スパークで出力ディレクトリを上書きする方法


107

毎分データセットを生成するスパークストリーミングアプリケーションがあります。処理したデータの結果を保存/上書きする必要があります。

データセットorg.apache.hadoop.mapred.FileAlreadyExistsExceptionを上書きしようとすると、実行が停止します。

Sparkプロパティを設定しましたset("spark.files.overwrite","true")が、うまくいきません。

スパークからファイルを上書きまたは事前削除するにはどうすればよいですか?


1
ええ、それは悪いことではありません、私はそれを0.9.0への回帰であると考えています。私の答えを受け入れてください:)
samthebest

set("spark.files.overwrite","true")を介して追加されたファイルに対してのみ機能しますspark.addFile()
aiman

回答:


106

更新:の使用を提案しDataframes、さらにのようなものを提案し... .write.mode(SaveMode.Overwrite) ...ます。

便利なヒモ:

implicit class PimpedStringRDD(rdd: RDD[String]) {
    def write(p: String)(implicit ss: SparkSession): Unit = {
      import ss.implicits._
      rdd.toDF().as[String].write.mode(SaveMode.Overwrite).text(p)
    }
  }

古いバージョンでは、

yourSparkConf.set("spark.hadoop.validateOutputSpecs", "false")
val sc = SparkContext(yourSparkConf)

1.1.0では、-confフラグ付きのspark-submitスクリプトを使用してconf設定を設定できます。

警告(古いバージョン):@piggyboxによると、Sparkにはバグがあり、ファイルを書き込むために必要なファイルのみが上書きされpart-、他のファイルは削除されないままになります。


29
対象Spark 1.4df.write.mode(SaveMode.Overwrite).parquet(path)
ハファム2015

Spark SQLの場合、Core SparkのSaveModeを定義するオプションがありますが、そのようなものはありません。saveAsTextFileやその他の変換のためのこの種の機能の一部を本当に望んでいます
Murtaza Kanchwala

3
隠れた問題:HDFSを介してフォルダー全体を一掃する@pzecevicのソリューションと比較して、このアプローチでは、Sparkは出力フォルダー内の同じファイル名のパーツファイルのみを上書きします。これはほとんどの場合に機能しますが、フォルダー内に別のSpark / Hadoopジョブからの追加パーツファイルなどが他にある場合、これらのファイルは上書きされません。
piggybox 2015年

6
また、df.write.mode(mode: String).parquet(path)Whereモードを使用することもできます。文字列には、「overwrite」、「append」、「ignore」、「error」を指定できます。
ライ麦

1
@avocadoうんそう思う、Spark APIはリリースごとに
どんどん


27

パラメータのドキュメントには、spark.files.overwriteSparkContext.addFile()ターゲットファイルが存在し、その内容がソースのファイルと一致しないときに追加されたファイルを上書きするかどうか」と書かれています。したがって、saveAsTextFilesメソッドには影響しません。

ファイルを保存する前にこれを行うことができます:

val hadoopConf = new org.apache.hadoop.conf.Configuration()
val hdfs = org.apache.hadoop.fs.FileSystem.get(new java.net.URI("hdfs://localhost:9000"), hadoopConf)
try { hdfs.delete(new org.apache.hadoop.fs.Path(filepath), true) } catch { case _ : Throwable => { } }

AASはここで説明されています:http : //apache-spark-user-list.1001560.n3.nabble.com/How-can-I-make-Spark-1-0-saveAsTextFile-to-overwrite-existing-file-td6696。 html


29
pysparkはどうですか?
javadba 2015年

'write.mode(SaveMode.Overwrite)'を使用するための次の答えは行く方法です
YaOg

hdfsは古いファイルをまだ削除しているため、新しいファイルが入ってくると削除する場合があります。
ジェイク、

25

pyspark.sql.DataFrame.saveのドキュメント(現在は1.3.1)から、DataFrameをmode='overwrite'保存するタイミングを指定できます。

myDataFrame.save(path='myPath', source='parquet', mode='overwrite')

これにより、残ったパーティションファイルも削除されることを確認しました。したがって、最初は10個のパーティション/ファイルと言っていたが、6個のパーティションしかなかったDataFrameでフォルダーを上書きした場合、結果のフォルダーには6個のパーティション/ファイルが含まれます。

モードオプションの詳細については、Spark SQLのドキュメントを参照してください。


2
真実で役立つ、ありがとう、ただしDataFrame固有のソリューション- spark.hadoop.validateOutputSpecsすべてのSpark APIで機能します。
samthebest 2015

何らかの理由で、spark.hadoop.validateOutputSpecs1.3では動作しませんでしたが、これは動作します。
Eric Walker

1
@samthebest save(... , mode=ルートを使用すると、同じSparkコンテキスト内でファイルのセットを上書きしたり、別のファイルを追加したりできます。spark.hadoop.validateOutputSpecsコンテキストごとに1つのモードだけに制限しませんか?
dnlbrky 2015

1
@dnlbrky OPは追加を要求しませんでした。私が言ったように、本当、便利ですが、不必要です。OPが「どうやって追加するのですか」と尋ねられた場合、幅広い範囲の回答を与えることができます。しかし、それについては触れません。また、データフレームのScalaバージョンにはタイプセーフティとチェック機能があるため、使用を検討することをお勧めします。たとえば、「上書き」のタイプミスがあると、DAGが評価されるまでわからないため、ビッグデータジョブでこれを行うことができます。 2時間後に!Scalaバージョンを使用している場合、コンパイラはすべてを事前にチェックします!かなりクールで、ビッグデータにとって非常に重要です。
samthebest

15

df.write.mode('overwrite').parquet("/output/folder/path")Pythonを使用して寄木細工のファイルを上書きする場合に機能します。これはスパーク1.6.2です。今後のバージョンではAPIが異なる可能性があります


はい、これは私の要件(Databricks)に最適です
Nick.McDermaid

4
  val jobName = "WordCount";
  //overwrite the output directory in spark  set("spark.hadoop.validateOutputSpecs", "false")
  val conf = new 
  SparkConf().setAppName(jobName).set("spark.hadoop.validateOutputSpecs", "false");
  val sc = new SparkContext(conf)

Spark 1のみ、最新バージョンで使用df.write.mode(SaveMode.Overwrite)
ChikuMiku、2018

3

このオーバーロードされたバージョンの保存機能は私にとってはうまくいきます:

yourDF.save(outputPath、org.apache.spark.sql.SaveMode.valueOf( "Overwrite"))

上記の例では、既存のフォルダを上書きします。savemodeはこれらのパラメーターも取ることができます(https://spark.apache.org/docs/1.4.0/api/java/org/apache/spark/sql/SaveMode.html):

Append:Appendモードは、DataFrameをデータソースに保存するときに、データ/テーブルが既に存在する場合、DataFrameのコンテンツが既存のデータに追加されることが期待されることを意味します。

ErrorIfExists:ErrorIfExistsモードは、DataFrameをデータソースに保存するときに、データがすでに存在する場合、例外がスローされることが予想されることを意味します。

無視:無視モードとは、DataFrameをデータソースに保存するときに、データが既に存在する場合、保存操作によってDataFrameの内容が保存されず、既存のデータが変更されないことが期待されることを意味します。


1

独自のカスタム出力形式を使用したい場合は、RDDを使用して目的の動作を取得することもできます。

次のクラスを見てください: FileOutputFormatFileOutputCommitter

ファイル出力形式には、出力ディレクトリが存在するかどうかをチェックするcheckOutputSpecsという名前のメソッドがあります。FileOutputCommitterには、通常、一時ディレクトリから最終的な場所にデータを転送するcommitJobがあります。

私はまだそれを確認できませんでした(空き時間があるとすぐにそれを実行します)が、理論的には:FileOutputFormatを拡張し、ディレクトリに例外をスローしないメソッドにcheckOutputSpecsをオーバーライドすると、既存のカスタム出力コミッターのcommitJobメソッドを使用して、RDDで目的の動作を実現できる可能性があるロジック(たとえば、ファイルの一部をオーバーライドし、その他を追加)を実行します。

出力形式は、saveAsNewAPIHadoopFileに渡されます(これは、ファイルを実際に保存するために呼び出されるsaveAsTextFileメソッドでもあります)。また、出力コミッターはアプリケーションレベルで構成されます。


あなたがそれを助けることができるなら、私はFileOutputCommitterのサブクラス化に近づくことを避けます:それは恐ろしいコードです。Hadoop 3.0は、FileOutputFormatがリファクタリングされたスーパークラス(PathOutputCommitter)のさまざまな実装を取ることができるプラグインポイントを追加します。NetflixからのS3は、パーティション化されたツリーにインプレース書き込みし、ジョブのコミット時に競合解決(失敗、削除、追加)のみを行い、更新されたパーティションでのみ
stevel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.