Spark_Transformation转换算子

RDD整体上分为Value类型、双Value类型和Key-Value类型

一、Value类型

1.map()映射

1)函数签名:

def map[U: ClassTag](f: T => U): RDD[U]

def map[U: ClassTag](f: T => U): RDD[U] = withScope {
    val cleanF = sc.clean(f)
    new MapPartitionsRDD[U, T](this, (context, pid, iter) => iter.map(cleanF))
  }

private[spark] class MapPartitionsRDD[U: ClassTag, T: ClassTag](    
      ......    
      override def getPartitions: Array[Partition] = firstParent[T].partitions    
      ......
}

protected[spark] def firstParent[U: ClassTag]: RDD[U] = {
    dependencies.head.rdd.asInstanceOf[RDD[U]]
  }

2)功能说明

        参数f是一个函数,它可以接收一个参数。当某个RDD执行map方法时,会遍历该RDD中的每一个数据项,并依次应用f函数,从而产生一个新的RDD。即,这个新RDD中的每一个元素都是原来RDD中每一个元素依次应用f函数而得到的。

3)需求说明:

创建一个1-4数组的RDD,两个分区,将所有元素*2形成新的RDD

 4)代码实现

/**
 * map
 * 对RDD中的元素进行映射
 */
object Spark06_Transformation_map {
  def main(args: Array[String]): Unit = {
    //创建Spark配置文件对象
    val conf: SparkConf = new SparkConf().setAppName("Spark01_CreateRDD_mem").setMaster("local[*]")
    //创建SparkContext对象,该对象时提交Spark App的入口
    val sc = new SparkContext(conf)

    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4) ,2)
    println("原分区" + rdd.partitions.size)


    //val newRdd: RDD[Int] = rdd.map((x:Int) =>{ x * 2})
    //简化
    val newRdd: RDD[Int] = rdd.map(_ * 2)

    println("新分区" + newRdd.partitions.size)


    newRdd.collect().foreach(println)

    //释放资源
    sc.stop()
  }
}

2.mapPartitions()以分区为单位执行Map 

1)函数签名:      

def mapPartitions[U: ClassTag](f: Iterator[T] => Iterator[U],preservesPartitioning: Boolean =false):RDD[U]

 f函数把每一个分区的数据分别放入到迭代器中,批处理

preservesPartitioning:是否保留上游RDD的分区信息,默认false

2)功能说明:

Map是一次处理一个元素,而mapPartitions一次处理一个分区数据。

3)需求说明:

创建一个RDD,4个元素,2个分区,使每个元素*2组成新的RDD

  4)代码实现

/**
 * 转换算子mapPartitions
 *  以分区为单位,对RDD中的元素进行映射
 */
object Spark02_Transformation_mapPartitons {
  def main(args: Array[String]): Unit = {
    //创建Spark配置文件对象
    val conf: SparkConf = new SparkConf().setAppName("Spark01_CreateRDD_mem").setMaster("local[*]")
    //创建SparkContext对象,该对象时提交Spark App的入口
    val sc = new SparkContext(conf)

    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)

    //以分区为单位,对RDD中的元素进行映射
    //一般适用于批量处理的操作,例如:将RDD中的元素插入到数据库中,需要连接数据库,如果每一个元素都创建一次连接,效率低下。可以对每个分区的元素创建连接插入
    /*rdd.mapPartitions(dates =>
      dates.map(_ * 2)
    ).foreach(println)
     */
    //简化
    rdd.mapPartitions(_.map(_ * 2)).foreach(println)
    //释放资源
    sc.stop()
  }
}

3.map()和mapPartitions()区别

1)map():

每次处理一条数据。

2)mapPartition():

每次处理一个分区的数据,这个分区的数据处理完后,原RDD中分区的数据才能释放,可能导致OOM。

3)当内存空间较大的时候建议使用mapPartition(),以提高处理效率。

4.mapPartitionsWithIndex()带分区

1)函数签名:

def mapPartitionsWithIndex[U: ClassTag]( f: (Int, Iterator[T]) => Iterator[U],  preservesPartitioning: Boolean = false): RDD[U]

//Int表示分区编号

2)功能说明:

类似于mapPartitions,比mapPartitions多一个整数参数表示分区号

3)需求说明:

        创建一个RDD,使每个元素跟所在分区号形成一个元组,组成一个新的RDD

每个分区只调用一次f函数,得到RDD2

 4)代码实现

/**
 * 转换算子mapPartitionsWithIndex
 * 以分区为单位,对RDD中的元素进行映射,并带有分区编号
 *    可以根据分区号,对某个分区做操作
 */
object Spark03_Transformation_mapPartitonsWithIndex {
  def main(args: Array[String]): Unit = {
    //创建Spark配置文件对象
    val conf: SparkConf = new SparkConf().setAppName("Spark01_CreateRDD_mem").setMaster("local[*]")
    //创建SparkContext对象,该对象时提交Spark App的入口
    val sc = new SparkContext(conf)

    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8), 5)

    //val newRdd: RDD[Int] = rdd.map(a => a * 2)
    //val newRdd: RDD[Int] = rdd.mapPartitions(a => a.map(b => b * 2))
    //创建一个RDD,使每个元素跟所在分区号形成一个元组,组成一个新的RDD
    /*val newRDD: RDD[(Int, Int)] = rdd.mapPartitionsWithIndex((index, datas) => {
      datas.map((index, _))
    })

     */
    
    //需求:第二个分区的数据*2,其它分区数据不变
    val newRDD: RDD[Int] = rdd.mapPartitionsWithIndex(
      (index, datas) => {
        index match {
          case 1 => datas.map(_ * 2)
          case _ => datas
        }
      }
    )
    newRDD.collect().foreach(println)
    
    //释放资源
    sc.stop()
  }
}

5.flatMap

1)函数签名:

def flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U]

2)功能说明:

        与map操作类似,将RDD中的每一个元素通过应用f函数依次转换为新的元素,并封装到RDD中。 区别:在flatMap操作中,f函数的返回值是一个集合,并且会将每一个该集合中的元素拆分出来放到新的RDD中。

3)需求说明:

创建一个集合,集合里面存储的还是子集合,把所有子集合中数据取出放入到一个大的集合中。

/**
 * 转换算子flatmap将RDD中的每一个元素通过应用f函数依次转换为新的元素,并封装到RDD中。
 */
object Spark01_Transformation_flatmap {
  def main(args: Array[String]): Unit = {
    //创建Spark配置文件对象
    val conf: SparkConf = new SparkConf().setAppName("Spark01_CreateRDD_mem").setMaster("local[*]")
    //创建SparkContext对象,该对象时提交Spark App的入口
    val sc = new SparkContext(conf)

    val rdd: RDD[List[Int]] = sc.makeRDD(List(List(1, 2), List(3,4),List(5,6),List(7,8)),2)

    //匿名函数输入输出相同不能简化
    val newRdd: RDD[Int] = rdd.flatMap(datas => datas)

    newRdd.collect().foreach(println)
    
    //释放资源
    sc.stop()
  }
}

6.glom()分区转换数组

1)函数签名:

def glom(): RDD[Array[T]]

2)功能说明:

        该操作将RDD中每一个分区变成一个数组,并放置在新的RDD中,数组中元素的类型与原分区中元素类型一致

3)需求说明:

创建一个2个分区的RDD,并将每个分区的数据放到一个数组,求出每个分区的最大值

 4)代码实现

/**
 * 转换算子glom
 *  将RDD中的每个分区变为一个数组,放置到新的RDD中,数组中元素的类型与原分区中的元素类型一致
 */
object Spark04_Transformation_glom {
  def main(args: Array[String]): Unit = {
    //创建Spark配置文件对象
    val conf: SparkConf = new SparkConf().setAppName("Spark01_CreateRDD_mem").setMaster("local[*]")
    //创建SparkContext对象,该对象时提交Spark App的入口
    val sc = new SparkContext(conf)

    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6), 2)

    println("--------------------------glom前---------------------------")

    rdd.mapPartitionsWithIndex((index,datas)=>{
      println(index+"---"+ datas.mkString(" "))
      datas
    }).collect()

    println("--------------------------glom后---------------------------")

    val newRDD: RDD[Array[Int]] = rdd.glom()

    newRDD.mapPartitionsWithIndex((index,datas)=>{
      //查看数组中元素使用next()函数
      println(index+"---"+ datas.next().mkString(" "))
        datas

    }).collect()
    
    //释放资源
    sc.stop()
  }
}

7.groupBy()分组

1)函数签名:

def groupBy[K](f: T => K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])]

2)功能说明:

分组,按照传入函数的返回值进行分组。将相同的key对应的值放入一个迭代器。

3)需求说明:

创建一个RDD,按照元素模以2的值进行分组。

4)代码实现: 

/**
 * 转换算子groupby
 * 按照传入函数的返回值进行分组。将相同的key对应的值放入一个迭代器
 */
object Spark05_Transformation_groupby {
  def main(args: Array[String]): Unit = {
    //创建Spark配置文件对象
    val conf: SparkConf = new SparkConf().setAppName("Spark01_CreateRDD_mem").setMaster("local[*]")
    //创建SparkContext对象,该对象时提交Spark App的入口
    val sc = new SparkContext(conf)

    /*val rdd: RDD[Int] = sc.makeRDD(List(1,2,3,4,5,6,7,8,9),3)
    println("==============groupBy分组前================")
    rdd.mapPartitionsWithIndex(
      (index,datas)=>{
        println(index + "---->" + datas.mkString(","))
        datas
      }
    ).collect()

    val newRDD: RDD[(Int, Iterable[Int])] = rdd.groupBy(_%2)
    println("==============groupBy分组后================")
    newRDD.mapPartitionsWithIndex(
      (index,datas)=>{
        println(index + "---->" + datas.mkString(","))
        datas
      }
    ).collect()

     */

    val rdd: RDD[String] = sc.makeRDD(List("hello", "nihao", "hi", "hadoop", "kafka", "scala", "hi"))
    // 按照首字母第一个单词相同分组
    val newRDD: RDD[(String, Ite
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值