Spark'da çıktı dizininin üzerine nasıl yazılır


108

Her dakika için bir veri seti üreten bir kıvılcım akışı uygulamam var. İşlenen verilerin sonuçlarını kaydetmem / üzerine yazmam gerekiyor.

Veri kümesinin üzerine yazmaya çalıştığımda org.apache.hadoop.mapred.FileAlreadyExistsException yürütmeyi durduruyor.

Spark özelliğini ayarladım set("spark.files.overwrite","true"), ancak şans yok.

Kıvılcım dosyalarının üzerine nasıl yazılır veya önceden silinir?


1
Evet berbat değil mi, 0.9.0'a bir gerileme olarak düşünüyorum. Lütfen cevabımı kabul edin :)
samthebest

set("spark.files.overwrite","true")sadece eklenen dosyalar için çalışırspark.addFile()
aiman

Yanıtlar:


107

GÜNCELLEME: Kullanmayı Dataframesve buna benzer bir şeyi önerin ... .write.mode(SaveMode.Overwrite) ....

Kullanışlı pezevenk:

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)
    }
  }

Daha eski sürümler için deneyin

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

1.1.0'da, --conf bayrağıyla birlikte spark-submit betiğini kullanarak conf ayarlarını yapabilirsiniz.

UYARI (eski sürümler): @piggybox'a göre, Spark'ta yalnızca dosyalarını yazmak için ihtiyaç duyduğu dosyaların üzerine yazacağı bir hata var, part-diğer dosyalar kaldırılmadan bırakılacak.


30
İçin Spark 1.4:df.write.mode(SaveMode.Overwrite).parquet(path)
Ha Pham

Spark SQL için, Core Spark için SaveMode'u tanımlama seçeneklerine sahipsiniz, buna benzer bir şeye sahip değilsiniz. SaveAsTextFile ve diğer dönüşümler için bu türden bir özellik gerçekten ister misiniz
Murtaza Kanchwala

3
Gizli bir sorun: @ pzecevic'in tüm klasörü HDFS aracılığıyla silme çözümü ile karşılaştırıldığında, bu yaklaşımda Spark yalnızca çıktı klasöründeki aynı dosya adına sahip parça dosyalarının üzerine yazacaktır. Bu çoğu zaman işe yarar, ancak klasörde başka bir Spark / Hadoop işinden fazladan parça dosyaları gibi başka bir şey varsa bu, bu dosyaların üzerine yazılmaz.
piggybox

6
Ayrıca, df.write.mode(mode: String).parquet(path)Nerede modunu da kullanabilirsiniz : Dize şu şekilde olabilir: "üzerine yaz", "ekleme", "yok say", "hata".
çavdar

1
@avocado Evet öyle düşünüyorum, Spark API'leri her sürümde daha da kötüleşiyor: P
samthebest


27

Parametrenin dokümantasyonu şunu spark.files.overwritesöyler: " SparkContext.addFile()Hedef dosya var olduğunda ve içeriği kaynağınkilerle eşleşmediğinde eklenen dosyaların üzerine yazılıp yazılmayacağı ." Bu nedenle, saveAsTextFiles metodu üzerinde etkisi yoktur.

Dosyayı kaydetmeden önce bunu yapabilirsiniz:

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 burada açıklanmıştır: 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 için ne dersiniz?
javadba

'Write.mode (SaveMode.Overwrite)' kullanmanın bir sonraki cevabı, gitmenin yoludur
YaOg

hdfs, eski dosyaları silmeye devam ettiği için yeni dosyaları geldiklerinde silebilir.
Jake

25

Gönderen pyspark.sql.DataFrame.save belgelerinde (şu anda 1.3.1 at) belirtebilirsiniz mode='overwrite'bir DataFrame kaydederken:

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

Bunun kalan bölüm dosyalarını bile kaldıracağını doğruladım. Öyleyse, başlangıçta 10 bölüm / dosya söylediyseniz, ancak daha sonra klasörün üzerine yalnızca 6 bölümlü bir DataFrame yazdıysanız, ortaya çıkan klasörde 6 bölüm / dosya olacaktır.

Mod seçenekleri hakkında daha fazla bilgi için Spark SQL belgelerine bakın .


2
Doğru ve yararlı, teşekkürler, ancak DataFrame'e özgü bir çözüm - spark.hadoop.validateOutputSpecstüm Spark API'lerinde çalışacaktır.
samthebest

Nedense, spark.hadoop.validateOutputSpecs1.3'te benim için çalışmadı, ama bu işe yarıyor.
Eric Walker

1
@samthebest Yol ile, save(... , mode=aynı Spark bağlamında bir dosya kümesinin üzerine yazabilir, başka bir dosya ekleyebilir, vb. Olmaz spark.hadoop.validateOutputSpecsbağlamda başına sadece bir moda sınırlamaz?
dnlbrky

1
@dnlbrky OP, eklemeyi istemedi. Dediğim gibi, doğru, faydalı ama gereksiz. OP "nasıl eklerim" diye sorduysa, bir dizi yanıt verilebilirdi. Ama buna girmeyelim. Ayrıca, tür güvenliği ve daha fazla kontrol özelliği olduğundan, DataFrame'in Scala sürümünü kullanmayı düşünmenizi tavsiye ederim - örneğin, "üzerine yazmada" bir yazım hatası varsa, bu DAG değerlendirilene kadar bunu bulamazsınız - ki bu, bir Büyük Veri işinde olabilir 2 saat sonra ol! Scala sürümünü kullanırsanız, derleyici her şeyi önceden kontrol edecektir! Büyük Veri için oldukça havalı ve çok önemli.
samthebest

15

df.write.mode('overwrite').parquet("/output/folder/path")python kullanarak bir parke dosyasının üzerine yazmak istiyorsanız çalışır. Bu, kıvılcım 1.6.2'de. API, sonraki sürümlerde farklı olabilir


Evet, bu ihtiyacım için harika çalışıyor (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)

Yalnızca Spark 1 için, en son sürüm kullanımındadf.write.mode(SaveMode.Overwrite)
ChikuMiku

3

Kaydetme işlevinin bu aşırı yüklenmiş sürümü benim için çalışıyor:

yourDF.save (outputPath, org.apache.spark.sql.SaveMode.valueOf ("Üzerine Yaz"))

Yukarıdaki örnek, mevcut bir klasörün üzerine yazacaktır. Savemode bu parametreleri de alabilir ( https://spark.apache.org/docs/1.4.0/api/java/org/apache/spark/sql/SaveMode.html ):

Ekleme : Ekleme modu, bir DataFrame'i bir veri kaynağına kaydederken, veri / tablo zaten mevcutsa, DataFrame içeriğinin mevcut verilere eklenmesinin beklendiği anlamına gelir.

ErrorIfExists : ErrorIfExists modu, bir DataFrame'i bir veri kaynağına kaydederken, veriler zaten mevcutsa bir istisna atılmasının beklendiği anlamına gelir.

Yoksay : Yoksay modu, bir DataFrame'i bir veri kaynağına kaydederken, veri zaten mevcutsa, kaydetme işleminin DataFrame içeriğini kaydetmemesi ve mevcut verileri değiştirmemesinin beklendiği anlamına gelir.


1

Kendi özel çıktı formatınızı kullanmak istiyorsanız, RDD ile de istenen davranışı elde edebilirsiniz.

Aşağıdaki sınıflara bir göz atın: FileOutputFormat , FileOutputCommitter

Dosya çıktı biçiminde, çıktı dizininin var olup olmadığını kontrol eden checkOutputSpecs adında bir yönteme sahipsiniz. FileOutputCommitter'da, genellikle verileri geçici dizinden son yerine aktaran commitJob'a sahipsiniz.

Henüz doğrulayamadım (birkaç boş dakikam olur olmaz bunu yapacağım) ama teorik olarak: FileOutputFormat'ı genişletirsem ve checkOutputSpecs'i dizinde istisna oluşturmayan bir yönteme geçersiz kılarsam ve İstediğim mantığı gerçekleştirmek için (örneğin bazı dosyaları geçersiz kılın, diğerlerini ekleyin) RDD'lerle de istenen davranışı elde edebileceğimden, özel çıktı işleyicimin commitJob yöntemi.

Çıktı biçimi şuna aktarılır: saveAsNewAPIHadoopFile (bu, dosyaları gerçekten kaydetmek için saveAsTextFile olarak adlandırılan yöntemdir). Ve Çıktı kaydedicisi, uygulama düzeyinde yapılandırılır.


Yardımcı olabilirseniz, FileOutputCommiter'in alt sınıflarına girmekten kaçınırım: bu korkutucu bir kod parçası. Hadoop 3.0, FileOutputFormat'ın yeniden düzenlenmiş bir üst sınıfın (PathOutputCommitter) farklı uygulamalarını alabileceği bir eklenti noktası ekler. Netflix'ten S3 olanı, bölümlenmiş bir ağaca yerinde yazacak, yalnızca iş tamamlamada ve yalnızca güncellenmiş bölümlerde çakışma çözümlemesi (başarısız, silme, ekleme) yapacak
stevel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.