Spark - phân vùng lại () so với hợp nhất ()


254

Theo Học Spark

Hãy nhớ rằng phân vùng lại dữ liệu của bạn là một hoạt động khá tốn kém. Spark cũng có một phiên bản repartition()được gọi là tối ưu hóa coalesce()cho phép tránh di chuyển dữ liệu, nhưng chỉ khi bạn giảm số lượng phân vùng RDD.

Một điểm khác biệt tôi nhận được là với repartition()số lượng phân vùng có thể tăng / giảm, nhưng với coalesce()số lượng phân vùng chỉ có thể giảm.

Nếu các phân vùng được trải rộng trên nhiều máy và coalesce()được chạy, làm thế nào nó có thể tránh được sự di chuyển dữ liệu?

Câu trả lời:


354

Nó tránh một shuffle đầy đủ . Nếu biết rằng số lượng đang giảm thì người thực thi có thể giữ dữ liệu trên số lượng phân vùng tối thiểu một cách an toàn, chỉ di chuyển dữ liệu khỏi các nút phụ, vào các nút mà chúng tôi giữ.

Vì vậy, nó sẽ đi một cái gì đó như thế này:

Node 1 = 1,2,3
Node 2 = 4,5,6
Node 3 = 7,8,9
Node 4 = 10,11,12

Sau đó coalescexuống 2 phân vùng:

Node 1 = 1,2,3 + (10,11,12)
Node 3 = 7,8,9 + (4,5,6)

Lưu ý rằng Nút 1 và Nút 3 không yêu cầu dữ liệu gốc của nó để di chuyển.


115
Cảm ơn vì sự trả lời. Các tài liệu nên nói tốt hơn minimize data movementthay vì avoiding data movement.
Praveen Sripati

12
Có trường hợp nào khi repartitionnên sử dụng thay vì coalesce?
Niemand

21
@Niemand Tôi nghĩ rằng tài liệu hiện tại bao gồm điều này khá tốt: github.com/apache/spark/blob/ mẹo Hãy nhớ rằng tất cả đều repartitionlà cuộc gọi coalescevới shuffletham số được đặt thành đúng. Hãy cho tôi biết nếu nó giúp được bạn.
Justin Pihony

2
Có thể giảm số lượng các tập tin phân vùng đang tồn tại? Tôi không có hdfs, nhưng vấn đề với nhiều tập tin.

2
sự phân chia lại sẽ chậm hơn về mặt thống kê vì nó không biết rằng nó đang bị thu hẹp ... mặc dù có lẽ họ có thể tối ưu hóa điều đó. Trong nội bộ, nó chỉ gọi sự kết hợp với một shuffle = truelá cờ
Justin Pihony

171

Câu trả lời của Justin thật tuyệt vời và câu trả lời này đi sâu hơn.

Các repartitionthuật toán thực hiện một shuffle đầy đủ và tạo phân vùng mới với dữ liệu đó là phân bố đều. Hãy tạo một DataFrame với các số từ 1 đến 12.

val x = (1 to 12).toList
val numbersDf = x.toDF("number")

numbersDf chứa 4 phân vùng trên máy của tôi.

numbersDf.rdd.partitions.size // => 4

Đây là cách dữ liệu được chia trên các phân vùng:

Partition 00000: 1, 2, 3
Partition 00001: 4, 5, 6
Partition 00002: 7, 8, 9
Partition 00003: 10, 11, 12

Chúng ta hãy thực hiện một shuffle đầy đủ với repartitionphương thức và lấy dữ liệu này trên hai nút.

val numbersDfR = numbersDf.repartition(2)

Đây là cách numbersDfRdữ liệu được phân vùng trên máy của tôi:

Partition A: 1, 3, 4, 6, 7, 9, 10, 12
Partition B: 2, 5, 8, 11

Các repartitionphương pháp làm cho phân vùng mới và đồng đều phân phối dữ liệu trong phân vùng mới (phân phối dữ liệu là hơn ngay cả đối với các tập dữ liệu lớn hơn).

Sự khác biệt giữa coalescerepartition

coalescesử dụng các phân vùng hiện có để giảm thiểu lượng dữ liệu được xáo trộn. repartitiontạo các phân vùng mới và thực hiện một shuffle đầy đủ. coalescedẫn đến các phân vùng có lượng dữ liệu khác nhau (đôi khi các phân vùng có kích thước khác nhau nhiều) và repartitiondẫn đến các phân vùng có kích thước gần bằng nhau.

coalescehay repartitionnhanh hơn?

coalescecó thể chạy nhanh hơn repartition, nhưng các phân vùng có kích thước không đồng đều thường hoạt động chậm hơn so với các phân vùng có kích thước bằng nhau. Thông thường bạn sẽ cần phân vùng lại bộ dữ liệu sau khi lọc một bộ dữ liệu lớn. tôi đã tìm thấyrepartition tổng thể nhanh hơn vì Spark được xây dựng để hoạt động với các phân vùng có kích thước bằng nhau.

NB Tôi đã tò mò quan sát rằng phân vùng lại có thể tăng kích thước dữ liệu trên đĩa . Đảm bảo chạy thử nghiệm khi bạn đang sử dụng phân vùng lại / kết hợp trên các bộ dữ liệu lớn.

Đọc bài đăng trên blog này nếu bạn muốn biết thêm chi tiết.

Khi bạn sử dụng kết hợp và phân chia lại trong thực tế


8
Câu trả lời tuyệt vời @Powers, nhưng dữ liệu trong Phân vùng A và B không bị lệch? Làm thế nào nó được phân phối đều?
anwartheravian

Ngoài ra, cách tốt nhất để có được kích thước phân vùng mà không gặp lỗi OOM. Tôi sử dụng rdd.glom().map(len).collect()nhưng nó cho rất nhiều lỗi OOM.
anwartheravian

8
@anwartheravian - Phân vùng A và Phân vùng B có kích thước khác nhau vì repartitionthuật toán không phân phối dữ liệu như nhau cho các tập dữ liệu rất nhỏ. Tôi đã từng repartitiontổ chức 5 triệu bản ghi thành 13 phân vùng và mỗi tệp nằm trong khoảng 89,3 MB đến 89,6 MB - điều đó khá bằng nhau!
Quyền hạn

1
@Powers điều này nhìn câu trả lời tốt hơn với chi tiết.
Xanh

1
Điều này giải thích sự khác biệt tốt hơn rất nhiều. Cảm ơn!
Abhi

22

Một điểm nữa cần lưu ý ở đây là, vì nguyên tắc cơ bản của Spark RDD là bất biến. Sự phân chia lại hoặc kết hợp sẽ tạo ra RDD mới. RDD cơ sở sẽ tiếp tục tồn tại với số lượng phân vùng ban đầu. Trong trường hợp trường hợp sử dụng yêu cầu duy trì RDD trong bộ đệm, thì điều tương tự phải được thực hiện đối với RDD mới được tạo.

scala> pairMrkt.repartition(10)
res16: org.apache.spark.rdd.RDD[(String, Array[String])] =MapPartitionsRDD[11] at repartition at <console>:26

scala> res16.partitions.length
res17: Int = 10

scala>  pairMrkt.partitions.length
res20: Int = 2

tốt đẹp này là rất quan trọng và ít nhất để dev scala có kinh nghiệm này, không rõ ràng - ví dụ, không phải phân vùng lại hay liên hiệp nỗ lực để sửa đổi dữ liệu, chỉ cách nó được phân phối qua các nút
Doug

1
@Harikrishnan vì vậy nếu tôi hiểu đúng các câu trả lời khác thì theo chúng trong trường hợp hợp nhất Spark sử dụng các phân vùng hiện có, tuy nhiên RDD là bất biến, bạn có thể mô tả cách Coalesce sử dụng các phân vùng hiện tại không? Theo hiểu biết của tôi, tôi nghĩ Spark nối thêm các phân vùng mới vào các phân vùng hiện có để kết hợp lại.
Explorer

Nhưng nếu RDD "cũ" không được sử dụng nữa như được biết bởi biểu đồ thực thi, nó sẽ bị xóa khỏi bộ nhớ nếu không được duy trì, phải không?
Markus

15

repartition - nên sử dụng nó trong khi tăng số lượng phân vùng, vì nó liên quan đến việc xáo trộn tất cả dữ liệu.

coalesce- nên sử dụng nó trong khi giảm số lượng phân vùng. Ví dụ: nếu bạn có 3 phân vùng và bạn muốn giảm xuống còn 2, coalescesẽ chuyển dữ liệu phân vùng thứ 3 sang phân vùng 1 và 2. Phân vùng 1 và 2 sẽ vẫn nằm trong cùng một thùng chứa. Mặt khác, repartitionsẽ xáo trộn dữ liệu trong tất cả các phân vùng, do đó việc sử dụng mạng giữa các nhà thi hành sẽ cao và nó sẽ ảnh hưởng đến hiệu suất.

coalescethực hiện tốt hơn repartitiontrong khi giảm số lượng phân vùng.


Giải thích hữu ích.
Narendra Maru

11

Những gì tiếp theo từ và tài liệu mã coalesce(n)là giống coalesce(n, shuffle = false)repartition(n)giống nhưcoalesce(n, shuffle = true)

Do đó, cả hai coalescerepartitioncó thể được sử dụng để tăng số lượng phân vùng

Với shuffle = true, bạn thực sự có thể kết hợp với một số lượng lớn hơn các phân vùng. Điều này hữu ích nếu bạn có một số lượng nhỏ các phân vùng, ví dụ 100, có khả năng với một vài phân vùng có kích thước lớn bất thường.

Một lưu ý quan trọng khác để làm nổi bật là nếu bạn giảm mạnh số lượng phân vùng, bạn nên cân nhắc sử dụng phiên bản được xáo trộncoalesce (giống như repartitiontrong trường hợp đó). Điều này sẽ cho phép tính toán của bạn được thực hiện song song trên các phân vùng cha (nhiều tác vụ).

Tuy nhiên, nếu bạn đang thực hiện một sự kết hợp quyết liệt, ví dụ numPartitions = 1, điều này có thể dẫn đến việc tính toán của bạn diễn ra trên ít nút hơn bạn muốn (ví dụ: một nút trong trường hợp numPartitions = 1). Để tránh điều này, bạn có thể vượt qua shuffle = true. Điều này sẽ thêm một bước xáo trộn, nhưng có nghĩa là các phân vùng ngược dòng hiện tại sẽ được thực thi song song (theo bất kỳ phân vùng hiện tại nào).

Xin vui lòng tham khảo câu trả lời liên quan ở đây


10

Tất cả các câu trả lời đang thêm một số kiến ​​thức tuyệt vời vào câu hỏi rất thường được hỏi này.

Vì vậy, theo truyền thống của dòng thời gian của câu hỏi này, đây là 2 xu của tôi.

Tôi thấy sự phân chia lại nhanh hơn sự kết hợp , trong trường hợp rất cụ thể.

Trong ứng dụng của tôi khi số lượng tệp mà chúng tôi ước tính thấp hơn ngưỡng nhất định, phân vùng lại hoạt động nhanh hơn.

Ý tôi là đây

if(numFiles > 20)
    df.coalesce(numFiles).write.mode(SaveMode.Overwrite).parquet(dest)
else
    df.repartition(numFiles).write.mode(SaveMode.Overwrite).parquet(dest)

Trong đoạn trích trên, nếu các tệp của tôi dưới 20, sự kết hợp sẽ mất mãi mãi để kết thúc trong khi phân vùng lại nhanh hơn nhiều và do đó, mã trên.

Tất nhiên, con số này (20) sẽ phụ thuộc vào số lượng công nhân và lượng dữ liệu.

Mong rằng sẽ giúp.


6

Phân vùng lại : Xáo trộn dữ liệu thành một số phân vùng MỚI.

Ví dụ. Khung dữ liệu ban đầu được phân vùng trong 200 phân vùng.

df.repartition(500): Dữ liệu sẽ được xáo trộn từ 200 phân vùng đến 500 phân vùng mới.

Hợp nhất : Trộn dữ liệu vào số lượng phân vùng hiện có.

df.coalesce(5): Dữ liệu sẽ được xáo trộn từ 195 phân vùng còn lại đến 5 phân vùng hiện có.


3

Tôi muốn thêm vào câu trả lời của Justin và Power rằng -

repartitionsẽ bỏ qua các phân vùng hiện có và tạo các phân vùng mới. Vì vậy, bạn có thể sử dụng nó để sửa chữa sai lệch dữ liệu. Bạn có thể đề cập các phím phân vùng để xác định phân phối. Sai lệch dữ liệu là một trong những vấn đề lớn nhất trong không gian vấn đề 'dữ liệu lớn'.

coalescesẽ làm việc với các phân vùng hiện có và xáo trộn một tập hợp con của chúng. Nó không thể sửa dữ liệu sai lệch nhiều như repartitionvậy. Do đó, ngay cả khi nó rẻ hơn, nó có thể không phải là thứ bạn cần.


3

Đối với tất cả các câu trả lời tuyệt vời tôi muốn thêm đó repartitionlà một trong những lựa chọn tốt nhất để tận dụng song song dữ liệu. Trong khicoalesce cung cấp một tùy chọn giá rẻ để giảm các phân vùng và nó rất hữu ích khi ghi dữ liệu lên HDFS hoặc một số bồn rửa khác để tận dụng lợi thế của việc ghi lớn.

Tôi đã tìm thấy điều này hữu ích khi viết dữ liệu ở định dạng sàn gỗ để có được lợi thế đầy đủ.


2

Đối với ai đó có vấn đề khi tạo một tệp csv duy nhất từ ​​PySpark (AWS EMR) làm đầu ra và lưu nó trên s3, sử dụng phân vùng lại giúp ích. Lý do là, hợp nhất không thể thực hiện một shuffle đầy đủ, nhưng phân vùng lại có thể. Về cơ bản, bạn có thể tăng hoặc giảm số lượng phân vùng bằng cách phân vùng lại, nhưng chỉ có thể giảm số lượng phân vùng (chứ không phải 1) bằng cách sử dụng kết hợp. Đây là mã cho bất cứ ai đang cố gắng viết một csv từ AWS EMR đến s3:

df.repartition(1).write.format('csv')\
.option("path", "s3a://my.bucket.name/location")\
.save(header = 'true')

0

Nói một cách đơn giản COALESCE: - chỉ để giảm không có phân vùng, Không xáo trộn dữ liệu, nó chỉ nén các phân vùng

SỬA CHỮA: - dành cho cả tăng và giảm không có phân vùng, nhưng việc xáo trộn diễn ra

Thí dụ:-

val rdd = sc.textFile("path",7)
rdd.repartition(10)
rdd.repartition(2)

Cả hai hoạt động tốt

Nhưng chúng ta thường đi cho hai điều này khi chúng ta cần xem đầu ra trong một cụm, chúng ta đi với điều này.


9
Cũng sẽ có sự di chuyển của dữ liệu với Than.
sun_dare

0

Nhưng bạn cũng nên đảm bảo rằng, dữ liệu sắp tới các nút kết hợp sẽ có cấu hình cao, nếu bạn đang xử lý dữ liệu lớn. Bởi vì tất cả dữ liệu sẽ được tải vào các nút đó, có thể dẫn đến ngoại lệ bộ nhớ. Mặc dù việc bồi thường là tốn kém, tôi thích sử dụng nó. Vì nó xáo trộn và phân phối dữ liệu như nhau.

Hãy khôn ngoan để lựa chọn giữa hợp nhất và phân chia lại.


0

Các repartitionthuật toán thực hiện một shuffle đầy đủ các dữ liệu và tạo ra các phân vùng có kích thước bằng nhau của dữ liệu. coalescekết hợp các phân vùng hiện có để tránh xáo trộn hoàn toàn.

Coalesce hoạt động tốt khi lấy RDD với nhiều phân vùng và kết hợp các phân vùng trên một nút worker để tạo RDD cuối cùng với ít phân vùng hơn.

Repartitionsẽ chia sẻ lại dữ liệu trong RDD của bạn để tạo ra số phân vùng cuối cùng mà bạn yêu cầu. Việc phân vùng DataFrames có vẻ như là một chi tiết triển khai ở mức độ thấp cần được quản lý bởi khung công tác, nhưng thực tế thì không. Khi lọc các DataFram lớn thành các tệp nhỏ hơn, bạn hầu như luôn luôn phân vùng lại dữ liệu. Bạn có thể sẽ thường xuyên lọc các DataFram lớn thành các dữ liệu nhỏ hơn, vì vậy hãy làm quen với việc phân vùng lại.

Đọc bài đăng trên blog này nếu bạn muốn biết thêm chi tiết.

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.