Spark - แบ่งพาร์ติชั่น () vs coalesce ()


254

อ้างอิงจาก Learning Spark

โปรดทราบว่าการแบ่งส่วนข้อมูลของคุณเป็นการดำเนินการที่ค่อนข้างแพง Spark ยังมีเวอร์ชันที่repartition()เรียกว่าออพติไมซ์coalesce()ที่ช่วยให้หลีกเลี่ยงการเคลื่อนย้ายข้อมูล แต่ถ้าคุณลดจำนวนพาร์ติชัน RDD

สิ่งหนึ่งที่ฉันได้รับคือมีrepartition()จำนวนพาร์ติชันสามารถเพิ่ม / ลดได้ แต่ด้วยcoalesce()จำนวนพาร์ติชันสามารถลดลงได้เท่านั้น

หากพาร์ติชั่นนั้นถูกกระจายไปทั่วเครื่องหลายเครื่องและcoalesce()ทำงานอยู่มันจะหลีกเลี่ยงการเคลื่อนย้ายข้อมูลได้อย่างไร?

คำตอบ:


354

มันหลีกเลี่ยงการสับเปลี่ยนเต็ม หากทราบว่ามีการลดจำนวนผู้ดำเนินการจะสามารถเก็บข้อมูลในจำนวนพาร์ติชันขั้นต่ำได้อย่างปลอดภัยเพียงย้ายข้อมูลออกจากโหนดเพิ่มเติมไปยังโหนดที่เราเก็บไว้

ดังนั้นมันจะเป็นดังนี้:

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

จากนั้นcoalesceลดพาร์ติชันลงเป็น 2:

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

โปรดสังเกตว่าโหนด 1 และโหนด 3 ไม่ต้องการข้อมูลต้นฉบับเพื่อย้าย


115
ขอบคุณสำหรับคำตอบ เอกสารควรจะพูดดีกว่าแทนminimize data movement avoiding data movement
Praveen Sripati

12
มีกรณีใด ๆ เมื่อrepartitionควรจะใช้แทนcoalesce?
Niemand

21
@Niemand ผมคิดว่าครอบคลุมเอกสารปัจจุบันนี้สวยดี: github.com/apache/spark/blob/...เก็บไว้ในใจว่าทั้งหมดrepartitionจะเป็นสายcoalesceที่มีshuffleการตั้งค่าพารามิเตอร์ที่แท้จริง แจ้งให้เราทราบหากช่วยได้
Justin Pihony

2
เป็นไปได้หรือไม่ที่จะลดจำนวนไฟล์พาร์ติชันที่มีอยู่? ฉันไม่มี hdfs แต่มีปัญหากับไฟล์จำนวนมาก

2
การแบ่งพาร์ติชันจะช้าลงเนื่องจากไม่ทราบว่ากำลังหดตัวลง ... ถึงแม้ว่าพวกเขาอาจจะปรับให้เหมาะสม ภายในนั้นเพียงเรียกรวมตัวกันพร้อมกับshuffle = trueธง
Justin Pihony

172

คำตอบของจัสตินนั้นยอดเยี่ยมและการตอบสนองนี้จะลึกซึ้งยิ่งขึ้น

repartitionอัลกอริทึมไม่สับเต็มรูปแบบและสร้างพาร์ทิชันใหม่ที่มีข้อมูลที่กระจายอย่างสม่ำเสมอ มาสร้าง DataFrame ด้วยตัวเลขตั้งแต่ 1 ถึง 12

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

numbersDf มี 4 พาร์ติชันบนเครื่องของฉัน

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

นี่คือวิธีแบ่งข้อมูลในพาร์ติชัน:

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

ลองทำแบบสุ่มด้วยrepartitionวิธีการและรับข้อมูลนี้บนสองโหนด

val numbersDfR = numbersDf.repartition(2)

นี่คือวิธีการnumbersDfRแบ่งพาร์ติชันข้อมูลบนเครื่องของฉัน:

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

repartitionวิธีทำให้พาร์ทิชันใหม่และทั่วถึงกระจายข้อมูลในพาร์ทิชันใหม่ (การกระจายข้อมูลที่มีมากยิ่งขึ้นสำหรับชุดข้อมูลขนาดใหญ่)

ความแตกต่างระหว่างcoalesceและrepartition

coalesceใช้พาร์ติชันที่มีอยู่เพื่อลดจำนวนข้อมูลที่ลดลง repartitionสร้างพาร์ติชันใหม่และสลับแบบเต็ม coalesceผลลัพธ์ในพาร์ติชันที่มีจำนวนข้อมูลที่แตกต่างกัน (บางครั้งพาร์ติชันที่มีขนาดแตกต่างกันมาก) และrepartitionผลลัพธ์ในพาร์ติชันที่มีขนาดเท่ากันโดยประมาณ

เป็นcoalesceหรือrepartitionเร็วกว่า?

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

NB ฉันสังเกตเห็นอย่างสงสัยว่าการแบ่งพาร์ติชันสามารถเพิ่มขนาดของข้อมูลบนดิสก์ได้ ตรวจสอบให้แน่ใจว่าได้ทำการทดสอบเมื่อคุณใช้การแบ่งพาร์ติชัน / เชื่อมต่อกันบนชุดข้อมูลขนาดใหญ่

อ่านโพสต์บล็อกนี้หากคุณต้องการรายละเอียดเพิ่มเติม

เมื่อใดที่คุณจะใช้การรวมตัวกันและการแบ่งส่วนในทางปฏิบัติ


8
คำตอบที่ยอดเยี่ยม @Powers แต่ไม่มีข้อมูลใน Partition A และ B ที่เอียงใช่ไหม มีการกระจายเท่า ๆ กันอย่างไร?
anwartheravian

นอกจากนี้วิธีที่ดีที่สุดในการรับขนาดพาร์ติชันโดยไม่มีข้อผิดพลาด OOM คืออะไร ฉันใช้rdd.glom().map(len).collect()แต่ให้ข้อผิดพลาด OOM มากมาย
anwartheravian

8
@anwartheravian - พาร์ติชัน A และพาร์ติชัน B มีขนาดแตกต่างกันเนื่องจากrepartitionอัลกอริทึมไม่กระจายข้อมูลเท่า ๆ กันสำหรับชุดข้อมูลขนาดเล็กมาก ฉันใช้repartitionเพื่อจัดระเบียบ 5 ล้านบันทึกเป็น 13 พาร์ทิชันและแต่ละไฟล์อยู่ระหว่าง 89.3 MB และ 89.6 MB - มันค่อนข้างเท่าเทียมกัน!
พลัง

1
@ ช่วยให้คำตอบนี้ดูดียิ่งขึ้นพร้อมรายละเอียด
สีเขียว

1
สิ่งนี้อธิบายความแตกต่างได้ดีกว่ามาก ขอบคุณ!
Abhi

22

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

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

ทำได้ดีนี่! นี้เป็นสิ่งสำคัญและอย่างน้อยเพื่อ dev สกาล่านี้มีประสบการณ์ไม่ชัดเจน - คือไม่repartitionมิได้รวมกันพยายามที่จะแก้ไขข้อมูลเพียงวิธีการที่จะกระจายไปทั่วโหนด
ดั๊ก

1
@Harikrishnan ดังนั้นถ้าฉันเข้าใจคำตอบอื่น ๆ อย่างถูกต้องตามนั้นในกรณีที่รวมกัน Spark ใช้พาร์ทิชันที่มีอยู่ แต่เป็น RDD ไม่เปลี่ยนรูปคุณสามารถอธิบายวิธี Coalesce ใช้พาร์ทิชันที่มีอยู่? ตามความเข้าใจของฉันฉันคิดว่า Spark ผนวกพาร์ติชั่นใหม่เข้ากับพาร์ติชั่นที่มีอยู่แล้วในการรวมกัน
Explorer

แต่ถ้า RDD "เก่า" ไม่ได้ใช้อีกต่อไปตามที่ทราบโดยกราฟการดำเนินการมันจะถูกล้างออกจากหน่วยความจำหากไม่ยืนยันจะไม่ได้ใช่หรือไม่
Markus

15

repartition - แนะนำให้ใช้ในขณะที่เพิ่มจำนวนพาร์ติชันเนื่องจากเกี่ยวข้องกับการสับข้อมูลทั้งหมด

coalesce- แนะนำให้ใช้ในขณะที่ลดจำนวนพาร์ติชัน ตัวอย่างเช่นถ้าคุณมี 3 พาร์ติชั่นและคุณต้องการลดพาร์ติชันเป็น 2 coalesceจะย้ายข้อมูลพาร์ติชั่นที่ 3 ไปยังพาร์ติชั่น 1 และ 2 พาร์ติชั่นที่ 1 และ 2 จะยังคงอยู่ในคอนเทนเนอร์เดียวกัน ในทางกลับกันrepartitionจะสุ่มข้อมูลในทุกพาร์ติชันดังนั้นการใช้เครือข่ายระหว่างผู้บริหารจะสูงและจะส่งผลกระทบต่อประสิทธิภาพ

coalesceทำงานได้ดีกว่าrepartitionในขณะที่ลดจำนวนพาร์ติชัน


คำอธิบายที่เป็นประโยชน์
Narendra Maru

11

สิ่งที่ตามมาจากรหัสและรหัสเอกสารนั้นcoalesce(n)เป็นสิ่งเดียวกันcoalesce(n, shuffle = false)และrepartition(n)เหมือนกันcoalesce(n, shuffle = true)

ดังนั้นทั้งcoalesceและrepartitionสามารถใช้เพื่อเพิ่มจำนวนพาร์ติชัน

ด้วยshuffle = trueคุณสามารถรวมกันเป็นพาร์ติชันจำนวนมากขึ้นได้ สิ่งนี้มีประโยชน์หากคุณมีพาร์ติชั่นจำนวนน้อยพูด 100 ซึ่งอาจมีพาร์ติชันบางส่วนที่มีขนาดใหญ่ผิดปกติ

สิ่งสำคัญอีกข้อที่ควรเน้นคือถ้าคุณลดจำนวนพาร์ติชันลงอย่างมากคุณควรพิจารณาใช้เวอร์ชันที่สับได้ของcoalesce(เช่นเดียวกับrepartitionในกรณีนั้น) สิ่งนี้จะช่วยให้การคำนวณของคุณขนานกันบนพาเรนต์พาร์ติชั่น (หลายงาน)

อย่างไรก็ตามหากคุณทำการรวมกันอย่างรุนแรงเช่นnumPartitions = 1อาจทำให้การคำนวณของคุณเกิดขึ้นบนโหนดน้อยกว่าที่คุณชอบ (เช่นหนึ่งโหนดในกรณีของnumPartitions = 1) shuffle = trueเพื่อหลีกเลี่ยงนี้คุณสามารถส่งผ่าน สิ่งนี้จะเพิ่มขั้นตอนการสลับ แต่หมายถึงพาร์ติชันอัปสตรีมปัจจุบันจะถูกดำเนินการแบบขนาน (ต่อการแบ่งพาร์ทิชันปัจจุบัน)

โปรดอ้างอิงคำตอบที่เกี่ยวข้องที่นี่


10

คำตอบทั้งหมดจะเพิ่มความรู้ที่ดีในคำถามที่ถามบ่อยนี้

ตามประเพณีของไทม์ไลน์ของคำถามนี้นี่คือ 2 เซ็นต์ของฉัน

ฉันพบว่าการแบ่งส่วนจะเร็วกว่าการรวมตัวกันในกรณีที่เฉพาะเจาะจงมาก

ในแอปพลิเคชันของฉันเมื่อจำนวนไฟล์ที่เราประเมินต่ำกว่าเกณฑ์ที่กำหนดการแบ่งพาร์ติชันจะทำงานได้เร็วขึ้น

นี่คือสิ่งที่ฉันหมายถึง

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

ในตัวอย่างด้านบนหากไฟล์ของฉันน้อยกว่า 20 รวมตัวกันใช้เวลานานจนจบในขณะที่การแบ่งพาร์ทิชันนั้นเร็วขึ้นมากและดังนั้นโค้ดข้างต้น

แน่นอนว่าจำนวนนี้ (20) จะขึ้นอยู่กับจำนวนของพนักงานและปริมาณของข้อมูล

หวังว่าจะช่วย


6

Repartition : สลับข้อมูลเป็นพาร์ติชั่นใหม่จำนวนมาก

เช่น. เฟรมข้อมูลเริ่มต้นถูกแบ่งพาร์ติชันเป็น 200 พาร์ติชั่น

df.repartition(500): ข้อมูลจะถูกสับเปลี่ยนจาก 200 พาร์ติชั่นไปเป็น 500 พาร์ติชั่นใหม่

เชื่อมต่อกัน: สลับข้อมูลเป็นจำนวนพาร์ติชันที่มีอยู่

df.coalesce(5): ข้อมูลจะถูกสับเปลี่ยนจากพาร์ติชันที่เหลือ 195 พาร์ติชั่นไปเป็น 5 พาร์ติชั่นที่มีอยู่


4

ฉันต้องการเพิ่มคำตอบของจัสตินและพาวเวอร์นั่น -

repartitionจะละเว้นพาร์ติชันที่มีอยู่และสร้างพาร์ติชันใหม่ ดังนั้นคุณสามารถใช้มันเพื่อแก้ไขข้อมูลที่เอียง คุณสามารถพูดถึงคีย์พาร์ติชันเพื่อกำหนดการแจกจ่าย Data skew เป็นหนึ่งในปัญหาที่ใหญ่ที่สุดในพื้นที่ปัญหา 'ข้อมูลขนาดใหญ่'

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


3

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

ฉันพบว่ามีประโยชน์เมื่อเขียนข้อมูลในรูปแบบ parquet เพื่อรับประโยชน์อย่างเต็มที่


2

สำหรับคนที่มีปัญหาในการสร้างไฟล์ csv ไฟล์เดียวจาก PySpark (AWS EMR) เป็นเอาต์พุตและบันทึกไว้ใน s3 โดยใช้การแบ่งพาร์ติชันช่วย เหตุผลคือการรวมกันไม่สามารถทำการสับแบบเต็มได้ แต่การแบ่งพาร์ติชันสามารถทำได้ โดยพื้นฐานแล้วคุณสามารถเพิ่มหรือลดจำนวนพาร์ติชันโดยใช้การแบ่งพาร์ติชัน แต่สามารถลดจำนวนพาร์ติชัน (แต่ไม่ใช่ 1) โดยใช้การรวมกัน นี่คือรหัสสำหรับทุกคนที่พยายามเขียน csv จาก AWS EMR ถึง s3:

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

0

ด้วยวิธีที่เรียบง่าย COALESCE: - มีไว้สำหรับลดจำนวนพาร์ติชันเท่านั้นไม่มีการสับของข้อมูลเพียงแค่บีบอัดพาร์ติชัน

การเปลี่ยนแปลง: - สำหรับทั้งการเพิ่มและลดจำนวนพาร์ติชัน แต่การสับจะเกิดขึ้น

ตัวอย่าง:-

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

ทั้งสองทำงานได้ดี

แต่โดยทั่วไปเราไปสองสิ่งนี้เมื่อเราต้องการเห็นผลลัพธ์ในหนึ่งคลัสเตอร์เราไปกับสิ่งนี้


9
จะมีการเคลื่อนไหวของข้อมูลกับ Coalese เช่นกัน
sun_dare

0

แต่คุณควรตรวจสอบให้แน่ใจว่าข้อมูลที่มารวมตัวกันโหนดควรมีการกำหนดค่าสูงถ้าคุณจัดการกับข้อมูลขนาดใหญ่ เพราะข้อมูลทั้งหมดจะถูกโหลดไปยังโหนดเหล่านั้นอาจนำไปสู่ข้อยกเว้นหน่วยความจำ แม้ว่าการซ่อมแซมจะมีค่าใช้จ่ายสูง แต่ฉันชอบที่จะใช้ เนื่องจากมันจะสับและกระจายข้อมูลอย่างเท่าเทียมกัน

ควรเลือกระหว่างการรวมกันและการแบ่งพาร์ติชัน


0

repartitionอัลกอริทึมไม่สับเต็มรูปแบบของข้อมูลและสร้างพาร์ทิชันขนาดที่เท่ากันของข้อมูล coalesceรวมพาร์ติชันที่มีอยู่เพื่อหลีกเลี่ยงการสลับแบบเต็ม

รวมตัวกันทำงานได้ดีสำหรับการ RDD กับพาร์ติชันจำนวนมากและการรวมพาร์ติชันบนโหนคนงานเดียวเพื่อสร้าง RDD สุดท้ายที่มีพาร์ติชันน้อยลง

Repartitionจะสับเปลี่ยนข้อมูลใน RDD ของคุณเพื่อสร้างจำนวนพาร์ติชันสุดท้ายที่คุณร้องขอ การแบ่งพาร์ติชันของ DataFrames ดูเหมือนว่ารายละเอียดการใช้งานระดับต่ำที่ควรจัดการโดยกรอบงาน แต่ไม่ใช่ เมื่อกรอง DataFrames ขนาดใหญ่ไปเป็นอันที่เล็กกว่าคุณควรแบ่งพาร์ติชั่นข้อมูลใหม่เสมอ คุณอาจกรอง DataFrames ขนาดใหญ่เป็นขนาดเล็กลงบ่อยครั้งดังนั้นควรใช้การแบ่งพาร์ติชันใหม่

อ่านโพสต์บล็อกนี้หากคุณต้องการรายละเอียดเพิ่มเติม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.