Cách ghi đè thư mục đầu ra trong spark


107

Tôi có một ứng dụng phát trực tuyến tia lửa tạo ra một tập dữ liệu cho mỗi phút. Tôi cần lưu / ghi đè kết quả của dữ liệu đã xử lý.

Khi tôi cố gắng ghi đè tập dữ liệu org.apache.hadoop.mapred.FileAlreadyExistsException ngừng thực thi.

Tôi đặt thuộc tính Spark set("spark.files.overwrite","true"), nhưng không có may mắn.

Làm cách nào để ghi đè hoặc Xóa trước các tệp khỏi tia lửa?


1
Vâng, thật tệ phải không, tôi coi đó là một hồi quy về 0.9.0. Hãy chấp nhận câu trả lời của tôi :)
samthebest

set("spark.files.overwrite","true")chỉ hoạt động cho các tệp được thêm vàospark.addFile()
aiman

Câu trả lời:


106

CẬP NHẬT: Đề xuất sử dụng Dataframes, cộng với một cái gì đó như ... .write.mode(SaveMode.Overwrite) ....

Tay ma cô:

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

Đối với các phiên bản cũ hơn, hãy thử

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

Trong 1.1.0, bạn có thể thiết lập cài đặt conf bằng cách sử dụng tập lệnh spark-submit với cờ --conf.

CẢNH BÁO (các phiên bản cũ hơn): Theo @piggybox, có một lỗi trong Spark nơi nó sẽ chỉ ghi đè lên các tệp cần thiết để ghi part-tệp của nó , bất kỳ tệp nào khác sẽ không được di chuyển.


29
Dành cho Spark 1.4:df.write.mode(SaveMode.Overwrite).parquet(path)
Hà Phạm

Đối với Spark SQL, bạn có các tùy chọn để xác định SaveMode cho Core Spark mà bạn không có bất kỳ thứ gì tương tự. Thực sự muốn một số loại tính năng đó cho saveAsTextFile và các phép biến đổi khác
Murtaza Kanchwala

3
Một vấn đề ẩn: so với giải pháp của @ pzecevic để xóa toàn bộ thư mục thông qua HDFS, trong cách tiếp cận này, Spark sẽ chỉ ghi đè các tệp phần có cùng tên tệp trong thư mục đầu ra. Điều này hầu hết hoạt động, nhưng nếu có thứ gì đó khác, chẳng hạn như các tệp phần bổ sung từ một công việc Spark / Hadoop khác trong thư mục, điều này sẽ không ghi đè các tệp này.
piggybox,

6
Bạn cũng có thể sử dụng df.write.mode(mode: String).parquet(path)chế độ Where: Chuỗi có thể là: "ghi đè", "nối thêm", "bỏ qua", "lỗi".
lúa mạch đen

1
@avocado Yup nghĩ vậy, các API Spark ngày càng trở nên tồi tệ hơn trong mỗi bản phát hành: P
samthebest 10/09/17


27

Tài liệu cho tham số spark.files.overwritecho biết điều này: "Có ghi đè lên các tệp được thêm vào SparkContext.addFile()khi tệp đích tồn tại và nội dung của nó không khớp với nội dung của nguồn hay không." Vì vậy, nó không ảnh hưởng đến phương thức saveAsTextFiles.

Bạn có thể làm điều này trước khi lưu tệp:

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 đã giải thích ở đây: http://apache-spark-user-list.1001560.n3.nabble.com/How-can-I-make-Spark-1-0-saveAsTextFile-to-overwrite-existing-file-td6696. html


29
những gì về pyspark?
javadba

Câu trả lời bên cạnh 'write.mode (SaveMode.Overwrite)' sử dụng là con đường để đi
YaOg

hdfs có thể xóa các tệp mới khi chúng xuất hiện vì nó vẫn đang xóa các tệp cũ.
Jake

25

Từ tài liệu pyspark.sql.DataFrame.save (hiện ở 1.3.1), bạn có thể chỉ định mode='overwrite'khi lưu DataFrame:

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

Tôi đã xác minh rằng điều này thậm chí sẽ xóa các tệp phân vùng còn sót lại. Vì vậy, nếu ban đầu bạn đã nói 10 phân vùng / tệp, nhưng sau đó ghi đè thư mục bằng DataFrame chỉ có 6 phân vùng, thư mục kết quả sẽ có 6 phân vùng / tệp.

Xem tài liệu Spark SQL để biết thêm thông tin về các tùy chọn chế độ.


2
Đúng và hữu ích, cảm ơn, nhưng một giải pháp DataFrame cụ thể - spark.hadoop.validateOutputSpecssẽ hoạt động trên tất cả các API Spark.
samthebest

Vì một số lý do, spark.hadoop.validateOutputSpecskhông hoạt động với tôi trên 1.3, nhưng điều này có.
Eric Walker

1
@samthebest Với save(... , mode=route, bạn có thể ghi đè một tập hợp các tệp, nối một tệp khác, v.v. trong cùng một ngữ cảnh Spark. Sẽ không spark.hadoop.validateOutputSpecsgiới hạn bạn chỉ ở một chế độ cho mỗi ngữ cảnh?
dnlbrky

1
@dnlbrky OP đã không yêu cầu thêm. Như tôi đã nói, đúng, hữu ích, nhưng không cần thiết. Nếu OP hỏi "làm cách nào để nối thêm" thì có thể đưa ra một loạt câu trả lời. Nhưng chúng ta không đi sâu vào đó. Ngoài ra, tôi khuyên bạn nên xem xét sử dụng phiên bản Scala của DataFrames vì ​​nó có tính an toàn về kiểu chữ và kiểm tra nhiều hơn - ví dụ: nếu bạn có lỗi đánh máy trong "ghi đè", bạn sẽ không phát hiện ra cho đến khi DAG đó được đánh giá - điều này trong công việc Dữ liệu lớn có thể là 2 giờ sau !! Nếu bạn sử dụng phiên bản Scala, trình biên dịch sẽ kiểm tra mọi thứ trước! Khá tuyệt và rất quan trọng đối với Dữ liệu lớn.
samthebest

15

df.write.mode('overwrite').parquet("/output/folder/path")hoạt động nếu bạn muốn ghi đè lên một tệp parquet bằng python. Đây là trong tia lửa 1.6.2. API có thể khác trong các phiên bản sau


Đúng, điều này hoạt động tốt cho yêu cầu của tôi (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)

Chỉ dành cho Spark 1, trong phiên bản mới nhất sử dụngdf.write.mode(SaveMode.Overwrite)
ChikuMiku

3

Phiên bản quá tải này của lưu hàm hợp với tôi:

yourDF.save (outputPath, org.apache.spark.sql.SaveMode.valueOf ("Ghi đè"))

Ví dụ trên sẽ ghi đè lên một thư mục hiện có. Chế độ lưu cũng có thể nhận các tham số này ( https://spark.apache.org/docs/1.4.0/api/java/org/apache/spark/sql/SaveMode.html ):

Nối : Chế độ nối có nghĩa là khi lưu DataFrame vào nguồn dữ liệu, nếu dữ liệu / bảng đã tồn tại, nội dung của DataFrame sẽ được nối vào dữ liệu hiện có.

ErrorIfExists : Chế độ ErrorIfExists có nghĩa là khi lưu DataFrame vào một nguồn dữ liệu, nếu dữ liệu đã tồn tại, một ngoại lệ sẽ được đưa ra.

Bỏ qua : Chế độ bỏ qua có nghĩa là khi lưu DataFrame vào nguồn dữ liệu, nếu dữ liệu đã tồn tại, hoạt động lưu dự kiến ​​sẽ không lưu nội dung của DataFrame và không thay đổi dữ liệu hiện có.


1

Nếu bạn sẵn sàng sử dụng định dạng đầu ra tùy chỉnh của riêng mình, bạn cũng sẽ có thể có được hành vi mong muốn với RDD.

Hãy xem các lớp sau: FileOutputFormat , FileOutputCommitter

Ở định dạng đầu ra tệp, bạn có một phương thức có tên là checkOutputSpecs, phương thức này đang kiểm tra xem thư mục đầu ra có tồn tại hay không. Trong FileOutputCommitter, bạn có commitJob thường chuyển dữ liệu từ thư mục tạm thời đến vị trí cuối cùng của nó.

Tôi chưa thể xác minh điều đó (sẽ làm điều đó ngay khi tôi có vài phút rảnh rỗi) nhưng về mặt lý thuyết: Nếu tôi mở rộng FileOutputFormat và ghi đè checkOutputSpecs thành một phương thức không ném ngoại lệ vào thư mục đã tồn tại và điều chỉnh Phương thức commitJob của trình cam kết đầu ra tùy chỉnh của tôi để thực hiện logic nào mà tôi muốn (ví dụ: Ghi đè một số tệp, nối các tệp khác) hơn là tôi có thể đạt được hành vi mong muốn với RDD.

Định dạng đầu ra được chuyển tới: saveAsNewAPIHadoopFile (đây cũng là phương thức mà saveAsTextFile được gọi để thực sự lưu các tệp). Và trình cam kết đầu ra được cấu hình ở cấp ứng dụng.


Tôi sẽ tránh đến gần phân lớp FileOutputCommitter nếu bạn có thể giúp nó: đó là một đoạn mã đáng sợ. Hadoop 3.0 thêm một điểm bổ sung nơi FileOutputFormat có thể thực hiện các triển khai khác nhau của lớp siêu được cấu trúc lại (PathOutputCommitter). Một S3 từ Netflix sẽ viết tại chỗ vào một cây phân vùng, chỉ làm giải quyết xung đột (thất bại, xóa, add) tại công việc cam kết, và duy nhất trong phân vùng được cập nhật
stevel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.