持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情
上篇我们说了Key-Value类型中的聚合算子,本文我们讲一下 分区算子partitionBy()、分组算子groupByKey()、排序算子sortByKey()。
1. partitionBy(): 按照K重新分区
def partitionBy(partitioner: Partitioner): RDD[(K, V)]
功能:将RDD[K,V]中的K按照指定Partitioner重新进行分区;
如果原有的RDD和新的RDD是一致的话就不进行分区,否则会产生Shuffle过程。如图所示
代码实现:
object KeyValue01_partitionBy {
def main(args: Array[String]): Unit = {
//1.创建SparkConf并设置App名称
val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
//2.创建SparkContext,该对象是提交Spark App的入口
val sc: SparkContext = new SparkContext(conf)
//3具体业务逻辑
//3.1 创建第一个RDD
val rdd: RDD[(Int, String)] = sc.makeRDD(Array((1,"aaa"),(2,"bbb"),(3,"ccc")),3)
//3.2 对RDD重新分区
val rdd2: RDD[(Int, String)] = rdd.partitionBy(new org.apache.spark.HashPartitioner(2))
//3.3 打印查看对应分区数据 (0,(2,bbb)) (1,(1,aaa)) (1,(3,ccc))
val indexRdd = rdd2.mapPartitionsWithIndex(
(index, datas) => datas.map((index,_))
)
indexRdd.collect().foreach(println)
//4.关闭连接
sc.stop()
}
}
复制代码
2. groupByKey(): 按照K重新分组(用的较少,Shuffle工作量大)
def groupByKey(): RDD[(K, Iterable[V])]
功能:groupByKey对每个key进行操作,但只生成一个seq,并不进行聚合。可以指定分区器或者分区数(默认使用HashPartitioner)
注意:从图中我们可以看出,groupByKey算子没有预聚合的过程,直接进行Shuffle,所以在硬盘上交换的数据量大,导致Shuffle工作效率低,容易出现数据倾斜的问题,所以groupByKey算子不常用。
需求实现代码如下:
object KeyValue03_groupByKey {
def main(args: Array[String]): Unit = {
//1.创建SparkConf并设置App名称
val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
//2.创建SparkContext,该对象是提交Spark App的入口
val sc: SparkContext = new SparkContext(conf)
//3具体业务逻辑
//3.1 创建第一个RDD
val rdd = sc.makeRDD(List(("a",1),("b",5),("a",5),("b",2)))
//3.2 将相同key对应值聚合到一个Seq中
val group: RDD[(String, Iterable[Int])] = rdd.groupByKey()
//3.3 打印结果
group.collect().foreach(println)
//3.4 计算相同key对应值的相加结果
group.map(t=>(t._1,t._2.sum)).collect().foreach(println)
//4.关闭连接
sc.stop()
}
}
复制代码
3. sortByKey(): 按照K进行排序
def sortByKey(
ascending: Boolean = true, // 默认,升序
numPartitions: Int = self.partitions.length) : RDD[(K, V)]
复制代码
功能:返回一个按照 key 排序的 (K.V) 的RDD,默认是升序排序。
实现代码如下:
object KeyValue07_sortByKey {
def main(args: Array[String]): Unit = {
//1.创建SparkConf并设置App名称
val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
//2.创建SparkContext,该对象是提交Spark App的入口
val sc: SparkContext = new SparkContext(conf)
//3具体业务逻辑
//3.1 创建第一个RDD
val rdd: RDD[(Int, String)] = sc.makeRDD(Array((3,"aa"),(6,"cc"),(2,"bb"),(1,"dd")))
//3.2 按照key的正序(默认顺序)
rdd.sortByKey(true).collect().foreach(println)
//3.3 按照key的倒序
rdd.sortByKey(false).collect().foreach(println)
//4.关闭连接
sc.stop()
}
}
复制代码
4. mapValues(): 只对V进行操作
def mapValues[U](f: V => U): RDD[(K, U)]
功能:针对于(K,V)形式的类型只对 V 进行操作
实现代码:
object KeyValue08_mapValues {
def main(args: Array[String]): Unit = {
//1.创建SparkConf并设置App名称
val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
//2.创建SparkContext,该对象是提交Spark App的入口
val sc: SparkContext = new SparkContext(conf)
//3.具体业务逻辑
//3.1 创建第一个RDD
val rdd: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (1, "d"), (2, "b"), (3, "c")))
//3.2 对value添加字符串 "`"
rdd.mapValues(_ + "`").collect().foreach(println)
//4.关闭连接
sc.stop()
}
}
复制代码
5. join():等同于sql里的内连接,关联上的要,关联不上的舍弃(用的不多)
def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))]
def join[W](other: RDD[(K, W)], numPartitions: Int): RDD[(K, (V, W))]
复制代码
功能:在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的( K,(V,W) )的RDD
需求:我们要创建两个pairRDD,并将key相同的数据聚合到一个元组。图示如下:
注意:如果Key只是某一个RDD有,那么这个Key不会关联
代码实现如下:
object KeyValue09_join {
def main(args: Array[String]): Unit = {
//1.创建SparkConf并设置App名称
val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
//2.创建SparkContext,该对象是提交Spark App的入口
val sc: SparkContext = new SparkContext(conf)
//3具体业务逻辑
//3.1 创建第一个RDD
val rdd: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c")))
//3.2 创建第二个pairRDD
val rdd1: RDD[(Int, Int)] = sc.makeRDD(Array((1, 4), (2, 5), (4, 6)))
//3.3 join操作并打印结果
rdd.join(rdd1).collect().foreach(println)
//4.关闭连接
sc.stop()
}
}
复制代码
总结
至此,Key-Value类型的所有算子更新完毕,正在学习Spark RDD算子的同学可以认真看下 上篇(Transformation转换算子简单介绍--Key-Value类型(二)--聚合算子(上) - 掘金 (juejin.cn))、下两篇文章,希望大家可以有所收获。