feat:ChatGPT第 5 课:Partition 分区
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package org.exercises.exercises5.demo
|
||||
|
||||
/*
|
||||
* Spark 第 5 课:Partition 分区*/
|
||||
|
||||
import org.apache.spark.rdd.RDD
|
||||
import org.apache.spark.{SparkConf, SparkContext}
|
||||
|
||||
object Demo1PartitionBasic {
|
||||
def main(args: Array[String]): Unit = {
|
||||
val conf = new SparkConf().setAppName("Demo1PartitionBasic").setMaster("local")
|
||||
val sc = new SparkContext(conf)
|
||||
val rdd = sc.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8), 2)
|
||||
println("=============获取分区===========")
|
||||
println("=============获取分区===========")
|
||||
println(rdd.getNumPartitions) // 2
|
||||
|
||||
println("=============查看分区的数据===========")
|
||||
val res = rdd.glom()
|
||||
println(res.collect().toList) // List([I@7d755813, [I@69c93ca4)
|
||||
|
||||
// 分区 0: 1, 2, 3, 4
|
||||
// 分区 1: 5, 6, 7, 8
|
||||
printPartition(res)
|
||||
|
||||
println("=============Transformation 一般会不会改变 Partition 数?===========")
|
||||
println("=============Transformation 一般会不会改变 Partition 数?===========")
|
||||
val rddMap = sc.parallelize(
|
||||
List(1, 2, 3, 4, 5, 6),
|
||||
2
|
||||
)
|
||||
|
||||
val rddMap2 = rddMap.map(_ * 10)
|
||||
// Partition 0
|
||||
// 1 2 3
|
||||
// ↓ map
|
||||
// 10 20 30
|
||||
//
|
||||
// Partition 1
|
||||
// 4 5 6
|
||||
// ↓ map
|
||||
// 40 50 60
|
||||
// map 是在原有 Partition 中进行转换
|
||||
println(s"map前:${rddMap.getNumPartitions}")
|
||||
println(s"map后:${rddMap2.getNumPartitions}")
|
||||
println(rddMap2.toDebugString)
|
||||
|
||||
// map
|
||||
// filter
|
||||
// flatMap
|
||||
// 这类算子通常属于窄依赖,数据不需要大规模跨 Partition 重分配。
|
||||
|
||||
sc.stop()
|
||||
}
|
||||
|
||||
private def printPartition(res: RDD[Array[Int]]): Unit = {
|
||||
res.collect().zipWithIndex.foreach {
|
||||
case (data, index) =>
|
||||
println(s"分区 $index: ${data.mkString(", ")}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package org.exercises.exercises5.demo
|
||||
|
||||
/*
|
||||
* 什么操作会导致 Shuffle?*/
|
||||
|
||||
import org.apache.spark.{SparkConf, SparkContext}
|
||||
|
||||
object Demo2Shuffle {
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
|
||||
val conf = new SparkConf()
|
||||
.setAppName("ShuffleDemo")
|
||||
.setMaster("local[2]")
|
||||
|
||||
val sc = new SparkContext(conf)
|
||||
|
||||
val rdd = sc.parallelize(
|
||||
List(
|
||||
("A", 1),
|
||||
("B", 2),
|
||||
("A", 3),
|
||||
("B", 4),
|
||||
("A", 5),
|
||||
("B", 6)
|
||||
),
|
||||
2
|
||||
)
|
||||
|
||||
// 查看原始 RDD 每个 Partition 里面的数据
|
||||
println("========== 原始 RDD ==========")
|
||||
|
||||
rdd.glom().collect().zipWithIndex.foreach {
|
||||
case (data, index) =>
|
||||
println(s"Partition $index: ${data.toList}")
|
||||
}
|
||||
|
||||
|
||||
// ==========================
|
||||
// reduceByKey
|
||||
// ==========================
|
||||
|
||||
println("\n========== reduceByKey ==========")
|
||||
|
||||
val reduceRdd = rdd.reduceByKey(_ + _, 2)
|
||||
|
||||
println("reduceByKey 后的 Partition:")
|
||||
|
||||
reduceRdd.glom().collect().zipWithIndex.foreach {
|
||||
case (data, index) =>
|
||||
println(s"Partition $index: ${data.toList}")
|
||||
}
|
||||
|
||||
println("\nreduceByKey 的依赖关系:")
|
||||
println(reduceRdd.toDebugString)
|
||||
|
||||
|
||||
// ==========================
|
||||
// groupByKey
|
||||
// ==========================
|
||||
|
||||
println("\n========== groupByKey ==========")
|
||||
|
||||
val groupRdd = rdd.groupByKey(2)
|
||||
|
||||
println("groupByKey 后的 Partition:")
|
||||
|
||||
groupRdd.glom().collect().zipWithIndex.foreach {
|
||||
case (data, index) =>
|
||||
println(s"Partition $index: ${data.toList}")
|
||||
}
|
||||
|
||||
println("\ngroupByKey 的依赖关系:")
|
||||
println(groupRdd.toDebugString)
|
||||
|
||||
|
||||
sc.stop()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.exercises.exercises5.demo
|
||||
|
||||
/*
|
||||
* 现在我们开始主动控制 PairRDD 的分区方式。*/
|
||||
|
||||
import org.apache.spark.{HashPartitioner, SparkConf, SparkContext}
|
||||
|
||||
object Demo3PartitionBy {
|
||||
def main(args: Array[String]): Unit = {
|
||||
val conf = new SparkConf()
|
||||
.setAppName("Demo3PartitionBy")
|
||||
.setMaster("local")
|
||||
val sc = new SparkContext(conf)
|
||||
val rdd = sc.parallelize(
|
||||
List(
|
||||
("A", 1),
|
||||
("B", 2),
|
||||
("C", 3),
|
||||
("D", 4)
|
||||
), 5
|
||||
)
|
||||
println("partitionByq前:" + rdd.getNumPartitions)
|
||||
val result = rdd.partitionBy(new HashPartitioner(2))
|
||||
println("partitionByq后:" + result.getNumPartitions)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.exercises.exercises5.demo
|
||||
|
||||
/*
|
||||
* 奇数偶数分区*/
|
||||
|
||||
import org.apache.spark.{Partitioner, SparkConf, SparkContext}
|
||||
|
||||
|
||||
object Demo4MyPartitioner {
|
||||
def main(args: Array[String]): Unit = {
|
||||
val conf = new SparkConf()
|
||||
.setAppName("MyApp")
|
||||
.setMaster("local")
|
||||
val sc = new SparkContext(conf)
|
||||
val pairRDD = sc.parallelize(
|
||||
List(
|
||||
(1, "A"),
|
||||
(2, "B"),
|
||||
(3, "C"),
|
||||
(4, "D"),
|
||||
(5, "E"),
|
||||
(6, "F")
|
||||
), 5
|
||||
)
|
||||
val result = pairRDD.partitionBy(new MyPartitioner)
|
||||
println("partitionBy前:" + pairRDD.getNumPartitions)
|
||||
println("partitionBy后:" + result.getNumPartitions)
|
||||
result.glom().collect().foreach(x => println(x.mkString(",")))
|
||||
}
|
||||
}
|
||||
|
||||
class MyPartitioner extends Partitioner {
|
||||
|
||||
override def numPartitions: Int = 2
|
||||
|
||||
override def getPartition(key: Any): Int = {
|
||||
key.asInstanceOf[Int] % 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.exercises.exercises5.exercises
|
||||
|
||||
/*
|
||||
* Exercises1:观察 Partition
|
||||
创建:
|
||||
List(1, 2, 3, 4, 5, 6, 7, 8)
|
||||
并且指定:
|
||||
4 个 Partition
|
||||
要求打印:
|
||||
RDD 的 Partition 数量
|
||||
每个 Partition 中的数据
|
||||
提示使用:
|
||||
getNumPartitions()
|
||||
glom()
|
||||
collect()*/
|
||||
|
||||
import org.apache.spark.SparkConf
|
||||
import org.apache.spark.SparkContext
|
||||
|
||||
object Exercises1 {
|
||||
def main(args: Array[String]): Unit = {
|
||||
val conf = new SparkConf()
|
||||
.setAppName("Exercises1")
|
||||
.setMaster("local")
|
||||
val sc = new SparkContext(conf)
|
||||
val rdd = sc.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8), 4)
|
||||
println(rdd.getNumPartitions)
|
||||
rdd.glom().collect().zipWithIndex.foreach {
|
||||
case (data, index) =>
|
||||
println(s"Partition $index: ${data.toList}")
|
||||
}
|
||||
sc.stop()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.exercises.exercises5.exercises
|
||||
/*
|
||||
* Exercises2:观察 map 是否改变 Partition
|
||||
创建:
|
||||
List(1,2,3,4,5,6,7,8)
|
||||
4 个 Partition。
|
||||
然后:
|
||||
val result = rdd.map(_ * 10)
|
||||
打印:
|
||||
原 RDD Partition 数
|
||||
result Partition 数
|
||||
要求验证:
|
||||
map 前后 Partition 数是否相同。*/
|
||||
import org.apache.spark.{SparkConf, SparkContext}
|
||||
|
||||
object Exercises2 {
|
||||
def main(args: Array[String]): Unit = {
|
||||
val conf = new SparkConf()
|
||||
.setAppName("Exercises2")
|
||||
.setMaster("local")
|
||||
val sc = new SparkContext(conf)
|
||||
val rdd = sc.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8), 4)
|
||||
val result = rdd.map(_ * 10)
|
||||
println(rdd.getNumPartitions)
|
||||
println(result.getNumPartitions)
|
||||
sc.stop()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.exercises.exercises5.exercises
|
||||
|
||||
import org.apache.spark.{HashPartitioner, SparkConf, SparkContext}
|
||||
|
||||
/*
|
||||
* Exercises3:使用 partitionBy
|
||||
创建:
|
||||
List(
|
||||
("A", 1),
|
||||
("B", 2),
|
||||
("C", 3),
|
||||
("D", 4),
|
||||
("E", 5),
|
||||
("F", 6)
|
||||
)
|
||||
转换为 PairRDD。
|
||||
使用:
|
||||
new HashPartitioner(2)
|
||||
进行:
|
||||
partitionBy
|
||||
然后使用:
|
||||
glom()
|
||||
观察:
|
||||
数据最终进入了哪个 Partition。*/
|
||||
object Exercises3 {
|
||||
def main(args: Array[String]): Unit = {
|
||||
val conf = new SparkConf()
|
||||
.setAppName("Exercises3")
|
||||
.setMaster("local")
|
||||
val sc = new SparkContext(conf)
|
||||
val rdd = sc.parallelize(List(
|
||||
("A", 1),
|
||||
("B", 2),
|
||||
("C", 3),
|
||||
("D", 4),
|
||||
("E", 5),
|
||||
("F", 6)
|
||||
))
|
||||
val res = rdd.partitionBy(new HashPartitioner(2))
|
||||
res.glom().collect().zipWithIndex.foreach {
|
||||
case (value, index) =>
|
||||
println(s"Partition $index: ${value.mkString("Array(", ", ", ")")}")
|
||||
}
|
||||
sc.stop()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.exercises.exercises5.exercises
|
||||
|
||||
/*
|
||||
* Exercises4:自定义奇偶分区
|
||||
定义:
|
||||
class MyPartitioner extends Partitioner
|
||||
要求:
|
||||
偶数 → Partition 0
|
||||
奇数 → Partition 1
|
||||
数据:
|
||||
List(
|
||||
(1, "one"),
|
||||
(2, "two"),
|
||||
(3, "three"),
|
||||
(4, "four"),
|
||||
(5, "five"),
|
||||
(6, "six")
|
||||
)
|
||||
使用:
|
||||
partitionBy(new MyPartitioner)
|
||||
然后通过:
|
||||
glom()
|
||||
观察结果。
|
||||
预期:
|
||||
Partition 0:
|
||||
(2,two)
|
||||
(4,four)
|
||||
(6,six)
|
||||
|
||||
Partition 1:
|
||||
(1,one)
|
||||
(3,three)
|
||||
(5,five)*/
|
||||
|
||||
import org.apache.spark.{Partitioner, SparkConf, SparkContext}
|
||||
|
||||
object Exercises4 {
|
||||
def main(args: Array[String]): Unit = {
|
||||
val conf = new SparkConf()
|
||||
.setMaster("local")
|
||||
.setAppName("Exercises4")
|
||||
val sc = new SparkContext(conf)
|
||||
val rdd = sc.parallelize(List(
|
||||
(1, "one"),
|
||||
(2, "two"),
|
||||
(3, "three"),
|
||||
(4, "four"),
|
||||
(5, "five"),
|
||||
(6, "six")
|
||||
))
|
||||
val res = rdd.partitionBy(new MyPartitioner())
|
||||
res.glom().collect().zipWithIndex.foreach {
|
||||
case (arr, index) => println(s"分区 $index: ${arr.mkString(", ")}")
|
||||
}
|
||||
sc.stop()
|
||||
}
|
||||
}
|
||||
|
||||
// 一共有几个分区?
|
||||
// 数据怎么分?
|
||||
class MyPartitioner extends Partitioner {
|
||||
// 我的 RDD 一共有 2 个分区
|
||||
override def numPartitions: Int = 2
|
||||
|
||||
override def getPartition(key: Any): Int = {
|
||||
key.asInstanceOf[Int] % 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.exercises.exercises5.exercises
|
||||
|
||||
/*
|
||||
* Exercises25:综合题——观察 Shuffle
|
||||
创建:
|
||||
List(
|
||||
("A", 1),
|
||||
("B", 2),
|
||||
("A", 3),
|
||||
("B", 4),
|
||||
("A", 5),
|
||||
("C", 6)
|
||||
)
|
||||
要求完成两个版本。
|
||||
版本一
|
||||
groupByKey
|
||||
然后观察:
|
||||
glom()
|
||||
版本二
|
||||
reduceByKey(_ + _)
|
||||
然后观察:
|
||||
glom()
|
||||
最后打印:
|
||||
Partition 数量
|
||||
Partition 中的数据
|
||||
最终结果
|
||||
你不需要通过代码证明 Shuffle 的内部每一个细节,重点观察:
|
||||
groupByKey
|
||||
→ 分组后的数据
|
||||
|
||||
reduceByKey
|
||||
→ 聚合后的数据
|
||||
并思考:
|
||||
为什么两个算子的最终结果类似,但 Shuffle 阶段处理的数据量可能不同?*/
|
||||
|
||||
import org.apache.spark.{SparkConf, SparkContext}
|
||||
|
||||
object Exercises5 {
|
||||
def main(args: Array[String]): Unit = {
|
||||
val conf = new SparkConf()
|
||||
.setAppName("Exercises5")
|
||||
.setMaster("local")
|
||||
val sc = new SparkContext(conf)
|
||||
val rdd = sc.parallelize(List(
|
||||
("A", 1),
|
||||
("B", 2),
|
||||
("A", 3),
|
||||
("B", 4),
|
||||
("A", 5),
|
||||
("C", 6)
|
||||
), 4)
|
||||
println("=============原始数据==============")
|
||||
|
||||
println(rdd.getNumPartitions)
|
||||
rdd.glom().collect().zipWithIndex.foreach {
|
||||
case (value, index) => println(s"Partition $index: ${value.toList}")
|
||||
}
|
||||
|
||||
println("=============reduceByKey==============")
|
||||
val resRBK = rdd.reduceByKey(_ + _)
|
||||
println(resRBK.getNumPartitions)
|
||||
|
||||
resRBK.glom().collect().zipWithIndex.foreach {
|
||||
case (value, index) => println(s"Partition $index: ${value.toList}")
|
||||
}
|
||||
|
||||
|
||||
println("=============groupByKey==============")
|
||||
val resGBK = rdd.groupByKey()
|
||||
println(resGBK.getNumPartitions)
|
||||
|
||||
resGBK.glom().collect().zipWithIndex.foreach {
|
||||
case (value, index) => println(s"Partition $index: ${value.toList}")
|
||||
}
|
||||
sc.stop()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user