วิธีการเขียนทับไดเร็กทอรีเอาต์พุตใน spark


109

ฉันมีแอปพลิเคชั่นสตรีมประกายไฟซึ่งสร้างชุดข้อมูลสำหรับทุกนาที ฉันต้องการบันทึก / เขียนทับผลลัพธ์ของข้อมูลที่ประมวลผล

เมื่อฉันพยายามเขียนทับชุดข้อมูล org.apache.hadoop.mapred.FileAlreadyExistsException หยุดการดำเนินการ

ฉันตั้งค่าคุณสมบัติ Spark set("spark.files.overwrite","true")แต่ไม่มีโชค

จะเขียนทับหรือลบไฟล์จาก spark ได้อย่างไร?


1
ใช่มันไม่ได้แย่ฉันคิดว่ามันเป็นการถดถอยเป็น 0.9.0 โปรดยอมรับคำตอบของฉัน :)
samthebest

set("spark.files.overwrite","true")ใช้งานได้กับไฟล์ที่เพิ่มเข้ามาเท่านั้นspark.addFile()
aiman

คำตอบ:


108

UPDATE: แนะนำให้ใช้รวมทั้งสิ่งที่ชอบ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 script พร้อมแฟล็ก --conf

คำเตือน (เวอร์ชันเก่ากว่า): ตามที่ @piggybox มีข้อบกพร่องใน Spark ซึ่งจะเขียนทับเฉพาะไฟล์ที่ต้องใช้ในการเขียนpart-ไฟล์เท่านั้นไฟล์อื่น ๆ จะไม่ถูกลบออก


30
สำหรับSpark 1.4:df.write.mode(SaveMode.Overwrite).parquet(path)
ฮาฟาม

สำหรับ Spark SQL คุณมีตัวเลือกในการกำหนด SaveMode สำหรับ Core Spark ที่คุณไม่มีอะไรเช่นนั้น ต้องการคุณสมบัติบางอย่างสำหรับ saveAsTextFile และการเปลี่ยนแปลงอื่น ๆ
Murtaza Kanchwala

3
ปัญหาที่ซ่อนอยู่: เปรียบเทียบกับโซลูชันของ @ pzecevic ในการล้างข้อมูลทั้งโฟลเดอร์ผ่าน HDFS ในวิธีนี้ Spark จะเขียนทับไฟล์ส่วนที่มีชื่อไฟล์เดียวกันในโฟลเดอร์ผลลัพธ์เท่านั้น วิธีนี้ใช้งานได้เกือบตลอดเวลา แต่ถ้ามีอย่างอื่นเช่นไฟล์ส่วนพิเศษจากงาน Spark / Hadoop อื่นในโฟลเดอร์สิ่งนี้จะไม่เขียนทับไฟล์เหล่านี้
piggybox

6
คุณยังสามารถใช้df.write.mode(mode: String).parquet(path)Where mode: String can be: "overwrite", "append", "ignite", "error"
ข้าว

1
@avocado Yup คิดอย่างนั้น Spark API ก็แย่ลงเรื่อย ๆ ในทุกรุ่น: P
samthebest


27

เอกสารประกอบสำหรับพารามิเตอร์spark.files.overwriteระบุว่า: "จะเขียนทับไฟล์ที่เพิ่มเข้ามาSparkContext.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

คำตอบต่อไปในการใช้ 'write.mode (SaveMode.Overwrite)' คือวิธีที่จะไป
YaOg

hdfs อาจลบไฟล์ใหม่เมื่อเข้ามาเนื่องจากยังคงลบไฟล์เก่าอยู่
Jake

25

จากเอกสารคู่มือ pyspark.sql.DataFrame.save (ปัจจุบันอยู่ที่ 1.3.1) คุณสามารถระบุmode='overwrite'เมื่อบันทึก DataFrame:

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

ฉันได้ตรวจสอบแล้วว่าสิ่งนี้จะลบไฟล์พาร์ติชันที่เหลือ ดังนั้นถ้าคุณเคยพูด 10 พาร์ติชัน / ไฟล์ แต่เดิมเขียนทับโฟลเดอร์ด้วย DataFrame ที่มีเพียง 6 พาร์ติชันโฟลเดอร์ผลลัพธ์จะมีพาร์ติชัน / ไฟล์ 6 พาร์ติชั่น

ดูเอกสาร Spark SQLสำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกโหมด


2
ขอบคุณจริงและเป็นประโยชน์ แต่เป็นโซลูชันเฉพาะของ DataFrame spark.hadoop.validateOutputSpecsจะใช้ได้กับ Spark API ทั้งหมด
samthebest

ด้วยเหตุผลบางอย่างspark.hadoop.validateOutputSpecsไม่ได้ผลสำหรับฉันใน 1.3 แต่สิ่งนี้ทำได้
Eric Walker

1
@samthebest ด้วยsave(... , mode=เส้นทางนี้คุณสามารถเขียนทับไฟล์ชุดหนึ่งต่อท้ายอีกไฟล์ ฯลฯ ภายในบริบท Spark เดียวกัน จะไม่spark.hadoop.validateOutputSpecsจำกัด คุณเพียงหนึ่งโหมดต่อบริบท?
dnlbrky

1
@dnlbrky ทาง OP ไม่ได้ขอต่อท้าย อย่างที่บอกจริงมีประโยชน์ แต่ไม่จำเป็น หาก OP ถามว่า "ฉันจะต่อท้ายได้อย่างไร" จะสามารถให้คำตอบทั้งหมดได้ แต่อย่าเข้าไปในนั้น นอกจากนี้ฉันขอแนะนำให้คุณพิจารณาใช้ DataFrames เวอร์ชัน Scala เนื่องจากมีความปลอดภัยของประเภทและการตรวจสอบเพิ่มเติมเช่นหากคุณพิมพ์ผิดใน "เขียนทับ" คุณจะไม่พบจนกว่า DAG นั้นจะได้รับการประเมินซึ่งในงาน Big Data สามารถทำได้ ช้าไป 2 ชั่วโมง !! หากคุณใช้เวอร์ชัน Scala คอมไพเลอร์จะตรวจสอบทุกอย่างล่วงหน้า! ค่อนข้างเจ๋งและสำคัญมากสำหรับ Big Data
samthebest

15

df.write.mode('overwrite').parquet("/output/folder/path")ใช้งานได้หากคุณต้องการเขียนทับไฟล์ปาร์เก้โดยใช้ python นี่คือจุดประกาย 1.6.2 API อาจแตกต่างกันในเวอร์ชันหลัง ๆ


ใช่มันใช้งานได้ดีสำหรับความต้องการของฉัน (Databricks)
Nick.McD mermaid

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

3

ฟังก์ชันบันทึกเวอร์ชันที่โอเวอร์โหลดนี้ใช้ได้กับฉัน:

yourDF.save (outputPath, org.apache.spark.sql.SaveMode.valueOf ("เขียนทับ"))

ตัวอย่างด้านบนจะเขียนทับโฟลเดอร์ที่มีอยู่ savemode สามารถใช้พารามิเตอร์เหล่านี้ได้เช่นกัน ( https://spark.apache.org/docs/1.4.0/api/java/org/apache/spark/sql/SaveMode.html ):

Append : Append mode หมายความว่าเมื่อบันทึก DataFrame ลงในแหล่งข้อมูลหากมีข้อมูล / ตารางอยู่แล้วเนื้อหาของ DataFrame จะถูกผนวกเข้ากับข้อมูลที่มีอยู่

ErrorIfExists : โหมด ErrorIfExists หมายความว่าเมื่อบันทึก DataFrame ไปยังแหล่งข้อมูลหากมีข้อมูลอยู่แล้วคาดว่าจะมีข้อยกเว้นเกิดขึ้น

ละเว้น : โหมดไม่สนใจหมายความว่าเมื่อบันทึก DataFrame ลงในแหล่งข้อมูลหากมีข้อมูลอยู่แล้วการดำเนินการบันทึกคาดว่าจะไม่บันทึกเนื้อหาของ DataFrame และจะไม่เปลี่ยนแปลงข้อมูลที่มีอยู่


1

หากคุณยินดีที่จะใช้รูปแบบผลลัพธ์ที่กำหนดเองคุณจะสามารถรับพฤติกรรมที่ต้องการด้วย RDD ได้เช่นกัน

ดูคลาสต่อไปนี้: FileOutputFormat , FileOutputCommitter

ในรูปแบบไฟล์เอาต์พุตคุณมีเมธอดชื่อ checkOutputSpecs ซึ่งกำลังตรวจสอบว่ามีไดเร็กทอรีเอาต์พุตอยู่หรือไม่ ใน FileOutputCommitter คุณมีคอมมิตซึ่งมักจะถ่ายโอนข้อมูลจากไดเร็กทอรีชั่วคราวไปยังตำแหน่งสุดท้าย

ฉันยังไม่สามารถตรวจสอบได้ (จะทำทันทีที่ฉันมีเวลาว่างไม่กี่นาที) แต่ในทางทฤษฎี: ถ้าฉันขยาย FileOutputFormat และแทนที่ checkOutputSpecs เป็นวิธีการที่ไม่ทิ้งข้อยกเว้นในไดเรกทอรีที่มีอยู่แล้วและปรับ วิธีการกระทำของคอมมิทเตอร์เอาต์พุตที่กำหนดเองของฉันเพื่อดำเนินการตามตรรกะที่ฉันต้องการ (เช่นแทนที่ไฟล์บางไฟล์ต่อท้ายไฟล์อื่น ๆ ) มากกว่าที่ฉันอาจจะสามารถบรรลุพฤติกรรมที่ต้องการด้วย RDD ได้เช่นกัน

รูปแบบผลลัพธ์จะถูกส่งไปยัง: saveAsNewAPIHadoopFile (ซึ่งเป็นวิธีการที่เรียกว่า saveAsTextFile เพื่อบันทึกไฟล์จริงๆ) และคอมมิตเตอร์เอาต์พุตถูกกำหนดค่าที่ระดับแอ็พพลิเคชัน


ฉันจะหลีกเลี่ยงการเข้าใกล้ FileOutputCommitter ย่อยหากคุณสามารถช่วยได้นั่นเป็นรหัสที่น่ากลัว Hadoop 3.0 เพิ่มจุดปลั๊กอินที่ FileOutputFormat สามารถนำการใช้งาน superclass ที่ปรับโครงสร้างใหม่ (PathOutputCommitter) ไปใช้งานที่แตกต่างกัน S3 หนึ่งจาก Netflix จะเขียนในตำแหน่งลงในโครงสร้างที่แบ่งพาร์ติชันโดยทำการแก้ไขข้อขัดแย้งเท่านั้น (ล้มเหลวลบเพิ่ม) ที่งานคอมมิตและเฉพาะในพาร์ติชันที่อัปเดตเท่านั้น
stevel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.