Spark核心编程—RDD算子(转换算子)

文章目录

  • 持续更新中
  • 一、RDD转换算子
    • ( 一 )Value类型
      • 1、map
      • 2、mapPartitions
      • 3、mapPartitionWithIndex
      • 4、flatMap
      • 5、glom
      • 6、groupBy
      • 7、filter
      • 8、sample
      • 9、distinct
      • 10、coalesce
      • 11、repartition
      • 12、sortBy
    • ( 二 )双 Value 类型
      • 1、intersection
      • 2、union
      • 3、subtract
      • 4、zip
    • ( 三 )Key-Value类型
      • 1、partitionBy
      • 2、reduceByKey
      • 3、groupBykey
      • 4、aggregateByKey
      • 5、foldByKey
      • 6、combineByKey
      • 7、sortByKey
      • 8、join
      • 9、leftOuterjoin
      • 10、cogroup
  • 二、RDD行动算子

持续更新中

序号 算子名称 类型 函数说明
1 map Value 将处理的数据逐条映射转换(类型或者值的转换)
2 mapPartition Value 将待处理的数据以分区为单位发送到计算节点进行处理(可以进行任意处理,包括过滤数据)
3 mapPartitionWithIndex Value 将待处理的数据以分区为单位发送到计算节点进行处理,并获得当前分区索引
4 flatMap Value 将待处理的数据进行扁平化后再进行映射处理,也称之为扁平映射
5 glom Value 将同一个分区的数据直接转换为相同类型的内存数组进行处理,分区不变
6 groupBy Value 将数据根据指定的规则进行分组, 分区默认不变,数据重新组合,也称之为shuffle
7 filter Value 将数据根据指定的规则进行筛选过滤,符合规则,保留,不符则丢弃
8 sample Value 根据指定的规则从数据集中抽取数据
9 distinct Value 将数据集中重复的数据去重
10 coalesce Value 根据数据量缩减分区,用于大数据集过滤后,提高小数据集的执行效率
11 repartition Value 该操作内部其实执行的是 coalesce 操作,参数 shuffle 的默认值为 true
12 sortBy Value 该操作用于排序数据,默认为升序排列
13 intersection 双Value 对源 RDD 和参数 RDD 求交集后返回一个新的 RDD
14 union 双Value 对源 RDD 和参数 RDD 求并集后返回一个新的 RDD
15 subtract 双Value 以一个 RDD 元素为主,去除两个 RDD 中重复元素,将其他元素保留下来。求差集
16 zip 双Value 将两个 RDD 中的元素,以键值对的形式进行合并
17 partitionBy key-Value 将数据按照指定 Partitioner 重新进行分区
18 reduceByKey key-Value 将数据按照相同的 Key 对 Value 进行聚合
19 groupByKey key-Value 将数据根据 key 对 value 进行分组
20 aggregateByKey key-Value 将数据根据不同的规则进行分区内计算和分区间计算
21 foldByKey key-Value 当分区内计算规则和分区间计算规则相同时,aggregateByKey 就可以简化为 foldByKey
22 combineByKey key-Value 对 key-value 型 rdd 进行聚集操作
23 sortByKey key-Value 按照 key 进行排序
24 join key-Value 返回一个相同 key 对应的所有元素连接在一起的(K,(V,W))的 RDD
25 leftOuterJoin key-Value 类似于 SQL 语句的左外连接
26 cogroup key-Value 在类型为(K,V)和(K,W)的 RDD 上调用,返回一个(K,(Iterable,Iterable))类型的 RDD

一、RDD转换算子

1、Spark基础编程中的RDD算子也成为RDD方法,包括两大类,一类是转换算子,另一类是行动算子。RDD转换算子主要对旧的RDD包装成新的RDD,实现功能的补充与封装。RDD行动算子主要是触发任务的调度与执行。

2、RDD 根据数据处理方式的不同将算子整体上分为 Value 类型、双 Value 类型和 Key-Value类型。

( 一 )Value类型

1、map

函数说明:将处理的数据逐条进行映射转换,这里的转换可以是类型的转换,也可以是值的转换。

package Operator.transform
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object Spark01_RDD_Operator_Transform {
  def main(args: Array[String]): Unit = {
    val sparkConf=new SparkConf().setAppName("Operator").setMaster("local[*]")
    val sc=new SparkContext(sparkConf)

    //TODO 算子-map
    val rdd: RDD[Int] = sc.makeRDD(List(1, 3, 6, 8), 2)
    val maprdd3=rdd.map( _*2 )
    maprdd3.collect().foreach(println)

    sc.stop()
  }
}
//输出 2 6 12 16

2、mapPartitions

函数说明: 将待处理的数据以分区为单位发送到计算节点进行处理,这里的处理是指可以进行任意的处理,哪怕是过滤数据。

package Operator.transform
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark02_RDD_Operator_Transform_mapPartitions {
  def main(args: Array[String]): Unit = {
    val sparkConf=new SparkConf().setAppName("Operator").setMaster("local[*]")
    val sc=new SparkContext(sparkConf)


    //TODO 算子-mapPartitions
    val rdd: RDD[Int] = sc.makeRDD(List(1, 3, 6, 8), 2)
    //mapPartitions: 可以以分区为单位进行数据转换操作,会将整个分区的数据加载到内存中进行引用
    // 如果处理完的数据是不会被释放掉的,存在对象的引用。
    // 在内存较小,数据量较大的场合下,容易出现内存溢出

    val maprdd: RDD[Int] =rdd.mapPartitions(
    iter => {
      iter.map(_+2)
    })
    maprdd.collect().foreach(println)

    sc.stop()
  }
}
//输出 3 5 8 10

问题思考:map 和 mapPartitions的区别?

参考链接: http://t.csdn.cn/hq6bB

3、mapPartitionWithIndex

函数说明: 将待处理的数据以分区为单位发送到计算节点进行处理,这里的处理是指可以进行任意的处理,哪怕是过滤数据,在处理时同时可以获取当前分区索引。

package Operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark03_RDD_Operator_Transform_mapPartitionsWithIndex {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setAppName("Operator").setMaster("local[*]")
    val sc = new SparkContext(sparkConf)


    //TODO 算子-mapPartitionsWithIndex
    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 6, 8), 2) //后面的2代表分区数,从0开始,0:(1,2)   1:(6,8)

    /* 获取第二个数据分区的数据 */
    val mpirdd: RDD[Int] = rdd.mapPartitionsWithIndex(
      (index, iter) => {
        if (index == 1) {  
          iter
        }
        else {
          Nil.iterator //Nil:空集合,.iterator是迭代器,将空集合转换成迭代器的形式
        }
      })
    mpirdd.collect().foreach(println)
    sc.stop()
  }
}
//输出6,8

4、flatMap

函数说明: 将处理的数据进行扁平化后再进行映射处理,所以算子也称之为扁平映射

val dataRDD = sparkContext.makeRDD( List( List(1,2),List(3,4) ),1)
val dataRDD1 = dataRDD.flatMap(
 list => list
)
//输出 1,2,3,4

5、glom

函数说明: 将同一个分区的数据直接转换为相同类型的内存数组进行处理,分区不变
有点和flatMap功能相反,一个是将不同List中的数据合并在一个List中,另一个是根据分区将一个List中的数据分成多个List

package Operator.transform

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object Spark05_RDD_Operator_Transform_glom {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setAppName("Operator").setMaster("local[*]")
    val sc = new SparkContext(sparkConf)


    //TODO 算子-glom
    val rdd = sc.makeRDD(List(1,2,3,4),2)

    val glomrdd = rdd.glom()
    glomrdd.collect().foreach( data => println(data.mkString(" ")))
    
    sc.stop()
  }
}
// 输出(1,2) (3,4)

6、groupBy

函数说明: 将数据根据指定的规则进行分组, 分区默认不变,但是数据会被打乱重新组合,我们将这样的操作称之为 shuffle。
极限情况下,数据可能被分在同一个分区中。一个组的数据在一个分区中,但是并不是说一个分区中只有一个组

val dataRDD = sparkContext.makeRDD(List(1,2,3,4),1)
val dataRDD1 = dataRDD.groupBy( _%2 )

7、filter

函数说明: 将数据根据指定的规则进行筛选过滤,符合规则的数据保留,不符合规则的数据丢弃。
当数据进行筛选过滤后,分区不变,但是分区内的数据可能不均衡,生产环境下,可能会出现数据倾斜。

val dataRDD = sparkContext.makeRDD(List(1,2,3,4),1)
val dataRDD1 = dataRDD.filter(_%2 == 0)

8、sample

函数说明: 根据指定的规则从数据集中抽取数据

val dataRDD = sparkContext.makeRDD( List(1,2,3,4),1)
// 抽取数据不放回(伯努利算法)
// 伯努利算法:又叫 0、1 分布。例如扔硬币,要么正面,要么反面。
// 具体实现:根据种子和随机算法算出一个数和第二个参数设置几率比较,小于第二个参数要,大于不要
// 第一个参数:抽取的数据是否放回,false:不放回
// 第二个参数:抽取的几率,范围在[0,1]之间,0:全不取;1:全取;
// 第三个参数:随机数种子
val dataRDD1 = dataRDD.sample(false, 0.5)
// 抽取数据放回(泊松算法)
// 第一个参数:抽取的数据是否放回,true:放回;false:不放回
// 第二个参数:重复数据的几率,范围大于等于 0.表示每一个元素被期望抽取到的次数
// 第三个参数:随机数种子
val dataRDD2 = dataRDD.sample(true, 2)

9、distinct

函数说明: 将数据集中重复的数据去重

val dataRDD = sparkContext.makeRDD( List(1,2,3,4,1,2),1 )
val dataRDD1 = dataRDD.distinct()

10、coalesce

函数说明: 根据数据量缩减分区,用于大数据集过滤后,提高小数据集的执行效率
当 spark 程序中,存在过多的小任务的时候,可以通过 coalesce 方法,收缩合并分区,减少分区的个数,减小任务调度成本

val dataRDD = sparkContext.makeRDD(List(1,2,3,4,1,2),6)
val dataRDD1 = dataRDD.coalesce(2)

11、repartition

函数说明: 该操作内部其实执行的是 coalesce 操作,参数 shuffle 的默认值为 true。无论是将分区数多的RDD 转换为分区数少的 RDD,还是将分区数少的 RDD 转换为分区数多的 RDD,repartition操作都可以完成,因为无论如何都会经 shuffle 过程。

val dataRDD = sparkContext.makeRDD(List(1,2,3,4,1,2),2)
val dataRDD1 = dataRDD.repartition(4)

12、sortBy

函数说明: 该操作用于排序数据。在排序之前,可以将数据通过 f 函数进行处理,之后按照 f 函数处理的结果进行排序,默认为升序排列。排序后新产生的 RDD 的分区数与原 RDD 的分区数一致。中间存在 shuffle 的过程

val dataRDD = sparkContext.makeRDD(List(1,2,3,4,1,2),2)
val dataRDD1 = dataRDD.sortBy(num=>num, false, 4)

( 二 )双 Value 类型

1、intersection

函数说明: 对源 RDD 和参数 RDD 求交集后返回一个新的 RDD

val dataRDD1 = sparkContext.makeRDD(List(1,2,3,4))
val dataRDD2 = sparkContext.makeRDD(List(3,4,5,6))
val dataRDD = dataRDD1.intersection(dataRDD2)

2、union

函数说明: 对源 RDD 和参数 RDD 求并集后返回一个新的 RDD

val dataRDD1 = sparkContext.makeRDD(List(1,2,3,4))
val dataRDD2 = sparkContext.makeRDD(List(3,4,5,6))
val dataRDD = dataRDD1.union(dataRDD2)

3、subtract

函数说明: 以一个 RDD 元素为主,去除两个 RDD 中重复元素,将其他元素保留下来。求差集

val dataRDD1 = sparkContext.makeRDD(List(1,2,3,4))
val dataRDD2 = sparkContext.makeRDD(List(3,4,5,6))
val dataRDD = dataRDD1.subtract(dataRDD2)

4、zip

函数说明: 将两个 RDD 中的元素,以键值对的形式进行合并。其中,键值对中的 Key 为第 1 个 RDD中的元素,Value 为第 2 个 RDD 中的相同位置的元素。

val dataRDD1 = sparkContext.makeRDD(List(1,2,3,4))
val dataRDD2 = sparkContext.makeRDD(List(3,4,5,6))
val dataRDD = dataRDD1.zip(dataRDD2)
package Operator.transform

import org.apache.spark.{SparkConf, SparkContext}

object Spark13_RDD_Operator_Transform_doubleValue {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setAppName("doubleValue").setMaster("local[*]")
    val sc = new SparkContext(sparkConf)


    //TODO 算子-双value
    val dataRDD1 = sc.makeRDD(List(1,2,3,4))
    val dataRDD2 = sc.makeRDD(List(3,4,5,6))
    val interRDD = dataRDD1.intersection(dataRDD2)
    val unionRDD = dataRDD1.union(dataRDD2)
    val subtractRDD = dataRDD1.subtract(dataRDD2)
    val zipRDD = dataRDD1.zip(dataRDD2)
    interRDD.collect().foreach( println ) //输出3,4
    unionRDD.collect().foreach( println ) //输出1,2,3,4,3,4,5,6
    subtractRDD.collect().foreach( println ) //输出1,2
    zipRDD.collect().foreach( println ) //输出(1,3)(2,4)(3,5)(4,6)
    
    sc.stop()
  }
}

( 三 )Key-Value类型

1、partitionBy

函数说明: 将数据按照指定 Partitioner 重新进行分区。Spark 默认的分区器是 HashPartitioner

val rdd: RDD[(Int, String)] =
 sc.makeRDD(Array((1,"aaa"),(2,"bbb"),(3,"ccc")),3)
import org.apache.spark.HashPartitioner
val rdd2: RDD[(Int, String)] =
 rdd.partitionBy(new HashPartitioner(2))

2、reduceByKey

函数说明: 可以将数据按照相同的 Key 对 Value 进行聚合

val dataRDD1 = sparkContext.makeRDD(List(("a",1),("b",2),("c",3)))
val dataRDD2 = dataRDD1.reduceByKey(_+_)
val dataRDD3 = dataRDD1.reduceByKey(_+_, 2)

3、groupBykey

函数说明: 将数据源的数据根据 key 对 value 进行分组

val dataRDD1 =sparkContext.makeRDD(List(("a",1),("b",2),("c",3)))
val dataRDD2 = dataRDD1.groupByKey()
val dataRDD3 = dataRDD1.groupByKey(2)
val dataRDD4 = dataRDD1.groupByKey(new HashPartitioner(2))

4、aggregateByKey

函数说明: 将数据根据不同的规则进行分区内计算和分区间计算

val dataRDD1 =sparkContext.makeRDD(List(("a",1),("b",2),("c",3)))
val dataRDD2 =dataRDD1.aggregateByKey(0)(_+_,_+_)

例子:取出每个分区内相同 key 的最大值然后分区间相加

// TODO : 取出每个分区内相同 key 的最大值然后分区间相加
// aggregateByKey 算子是函数柯里化,存在两个参数列表
// 1. 第一个参数列表中的参数表示初始值
// 2. 第二个参数列表中含有两个参数
// 2.1 第一个参数表示分区内的计算规则
// 2.2 第二个参数表示分区间的计算规则
val rdd =sc.makeRDD(  List(("a",1),("a",2),("c",3),("b",4),("c",5),("c",6)),2 )
// 0:("a",1),("a",2),("c",3) => (a,10)(c,10)
// => (a,10)(b,10)(c,20)
// 1:("b",4),("c",5),("c",6) => (b,10)(c,10)
val resultRDD =
 rdd.aggregateByKey(10)(
 (x, y) => math.max(x,y),
 (x, y) => x + y
 )
resultRDD.collect().foreach(println)

5、foldByKey

函数说明: 当分区内计算规则和分区间计算规则相同时,aggregateByKey 就可以简化为 foldByKey

val dataRDD1 = sparkContext.makeRDD( List(("a",1),("b",2),("c",3)) )
val dataRDD2 = dataRDD1.foldByKey(0)(_+_)

6、combineByKey

函数说明: 最通用的对 key-value 型 rdd 进行聚集操作的聚集函数(aggregation function)。类似于aggregate(),combineByKey()允许用户返回值的类型与输入不一致。

//将数据 List(("a", 88), ("b", 95), ("a", 91), ("b", 93), ("a", 95), ("b", 98))求每个 key 的平均值
val list: List[(String, Int)] = List( ("a", 88), ("b", 95), ("a", 91), ("b", 93), ("a", 95), ("b", 98) )
val input: RDD[(String, Int)] = sc.makeRDD(list, 2)
val combineRdd: RDD[(String, (Int, Int))] = input.combineByKey(
 (_, 1),
 (acc: (Int, Int), v) => (acc._1 + v, acc._2 + 1),
 (acc1: (Int, Int), acc2: (Int, Int)) => (acc1._1 + acc2._1, acc1._2 + acc2._2)
)

7、sortByKey

函数说明: 在一个(K,V)的 RDD 上调用,K 必须实现 Ordered 接口(特质),返回一个按照 key 进行排序的

val dataRDD1 = sparkContext.makeRDD(List(("a",1),("b",2),("c",3)))
val sortRDD1: RDD[(String, Int)] = dataRDD1.sortByKey(true)
val sortRDD1: RDD[(String, Int)] = dataRDD1.sortByKey(false)

8、join

函数说明: 在类型为(K,V)和(K,W)的 RDD 上调用,返回一个相同 key 对应的所有元素连接在一起的(K,(V,W))的 RDD

val rdd: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c")))
val rdd1: RDD[(Int, Int)] = sc.makeRDD(Array((1, 4), (2, 5), (3, 6)))
rdd.join(rdd1).collect().foreach(println)

9、leftOuterjoin

函数说明: 类似于 SQL 语句的左外连接

val dataRDD1 = sparkContext.makeRDD(List(("a",1),("b",2),("c",3)))
val dataRDD2 = sparkContext.makeRDD(List(("a",1),("b",2),("c",3)))
val rdd: RDD[(String, (Int, Option[Int]))] = dataRDD1.leftOuterJoin(dataRDD2)

10、cogroup

函数说明: 在类型为(K,V)和(K,W)的 RDD 上调用,返回一个(K,(Iterable,Iterable))类型的 RDD

val dataRDD1 = sparkContext.makeRDD(List(("a",1),("a",2),("c",3)))
val dataRDD2 = sparkContext.makeRDD(List(("a",1),("c",2),("c",3)))
val value: RDD[(String, (Iterable[Int], Iterable[Int]))] = 
dataRDD1.cogroup(dataRDD2)

二、RDD行动算子

参考链接:Spark核心编程—RDD算子(行动算子)

你可能感兴趣的:(Spark,大数据面试,spark,big,data,hadoop)