Transformation转换算子简单介绍--Key-Value类型(二)--分区、排序算子(下)

持续创作,加速成长!这是我参与「掘金日新计划 · 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过程。如图所示

image.png

代码实现:

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)

image.png

注意:从图中我们可以看出,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,默认是升序排序。

image.png

实现代码如下:

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 进行操作

image.png

实现代码:

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相同的数据聚合到一个元组。图示如下:

image.png

注意:如果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))、下两篇文章,希望大家可以有所收获。

猜你喜欢

转载自juejin.im/post/7154911834829488165