SparkRDD——转换算子

本文深入介绍了Spark中的转换算子,包括单value型算子如map、flatMap、filter、sample和distinct,双value型算子如intersection、union和zip,以及键值类型算子如reduceByKey、groupByKey和join。详细阐述了各算子的使用场景、性能特点和数据处理逻辑,特别强调了coalesce与rePartition在分区调整中的差异及其最佳实践。
摘要由CSDN通过智能技术生成

转换算子

一、单value型转换算子(只使用1个RDD):
1、map                      将数据进行转换,数据量不会增加和减少
2、mapPartitions            以分区为单位将一个分区内的数据进行批处理操作,且可以执行过滤操作
3、mapPartitionsWithIndex   功能类似mapPartiutions算子,只是加入了每个分区的索引,可以选择性的对某些分区进行操作
4、flatMap                  扁平化操作,即将集合嵌套类型的数据或者可转换为嵌套集合的类型的数据转换为非嵌套集合
5、glom                     将元素合并为分区数量的数组,不需要传参数
6、groupBy                  通过给定函数计算所得key进行分组,返回一个键值对,键为key的类型,值为Iterable,有shuffer
7、filter                   将数据根据相应规则进行过滤,符合的保留,不符合的丢弃,过滤后分区不变。
8、sample                   抽样算子
9、distinct                 去重算子,将传入的数据集中相同的数据去除多余的保留一个
10、coalesce                缩减分区,默认不打乱分区,只是缩减分区,即将几个分区合并在一起
11、rePartition             扩大分区,扩大时必然会导致同一个分区的数据分到不同的分区,这就会发生shuffle
12、sortBy                  排序算子,将分区数据进行排序,分区数不变,但会产生shuffle
二、双value型转换算子(使用两个RDD):
1、intersection             对两个RDD求交集然后将结果封装为一个RDD,两个RDD数据类型必须一致
2、subtract                 对两个RDD求差集然后将结果封装为一个RDD,两个RDD数据类型必须一致
3、union                    求两个RDD元素的并集,然后将结果封装为一个RDD,两个RDD数据类型必须一致
4、zip                      将两个 RDD 中的元素以键值对的形式进行合并,不要求数据类型一致,但要求分区数一致且每个分区中元素数量一致
三、键值类型转换算子(数据源为键值对):
1、partitionBy              传入一个Partitioner进行重新分区,默认的分区器是HashPartitioner,也可以自定义分区器,存在shuffer
2、reduceByKey              将相同key的数据的value执行传入reduceByKey函数的操作,存在shuffer
3、groupByKey               根据key进行分组,分组后形成key,Iterator(value)格式的元组,存在shuffer
4、aggregateByKey           将分区内和分区间的计算分开,第一个参数列表传初始值,第二个参列表传递分区内和分区间计算规则,存在shuffer
5、foldByKey                作用和aggregate一样,当分区内函数和分区间函数相同时,spark提供了简化的算子foldByKey,存在shuffer
6、combineByKey             传入三个参数,第一个参数将value转换为指定数据类型,第二第三个参数表示分区内与分区间计算规则,存在shuffer
7、join                     对两个不同的数据源进行自然连接,相同的key的value会连接在一起形成元组,存在shuffer
8、leftOuterJoin            左外连接,以左边的数据为主,若左边数据存在,右边数据不存在,那么形成左边数据+None的组合,存在shuffer
9、rightOuterJoin           右外连接,以右边的数据为主,若右边数据存在,左边数据不存在,那么形成右边数据+None的组合,存在shuffer
10、cogroup                 首先在数据源内进行key的分组,再对两个数据源进行连接操作,存在shuffer


一、单value型转换算子(只使用1个RDD)

1、map

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

map算子将分区内的数据一个一个执行某个函数,类似串行操作,主要是将数据进行转换,数据不会增加和减少。

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

2、mapPartitions

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

mapPartitions算子以分区为单位将一个分区内的数据进行批处理操作,传入一个迭代器,输出一个迭代器,且可以执行过滤操作,因此元素个数可能发生增加或减少。

map和mapPartitions二者性能比较:map类似串行,mapPartitions类似批处理,因此后者性能较高。但mapPartitions算子计算时将分区数据全部加载进内存,等处理完整个分区后才释放内存,因此在内存不足的情况下建议使用map。

val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
val mapRDD1: RDD[Int] = rdd.map(
    (num: Int) => {
   
        println("map1 --- " + num)
        num
    }
)
val mapRDD2: RDD[Int] = mapRDD1.mapPartitions(
    (it: Iterator[Int]) => {
   
        println("map2 --- " + it)
        it
    }
)

在这里插入图片描述

3、mapPartitionsWithIndex

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

功能类似mapPartiutions算子,只是加入了每个分区的索引,可以选择性的对某些分区进行操作。

val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
val mpRDD: RDD[(Int, Int)] = rdd.mapPartitionsWithIndex(
    (index: Int, it: Iterator[Int]) => {
   
        it.map((index, _: Int))
    }
)
mpRDD.collect().foreach(println)

在这里插入图片描述

4、flatMap

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

扁平化操作,即将集合嵌套类型的数据或者可转换为嵌套集合的类型的数据转换为非嵌套集合

val rdd: RDD[List[Int]] = sc.makeRDD(List(List(1, 2), List(3, 4)))
val flatRDD: RDD[Int] = rdd.flatMap((list: List[Int]) => list)
flatRDD.collect().foreach(println)

在这里插入图片描述

5、glom

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

将元素合并为分区数量的数组,不需要传参数

val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
val glomRDD: RDD[Array[Int]] = rdd.glom()
glomRDD.collect().foreach((list: Array[Int]) => println(list.mkString(",")))

在这里插入图片描述

6、groupBy

def groupBy[K](f: T => K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])] = withScope {
   
    groupBy[K](f, defaultPartitioner(this))
}
def groupBy[K](
      f: T => K,
      numPartitions: Int)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])] = withScope {
   
    groupBy(f, new HashPartitioner(numPartitions))
}
def groupBy[K](f: T => K, p: Partitioner)(implicit kt: ClassTag[K], ord: Ordering[K] = null)
      : RDD[(K, Iterable[T])] = withScope {
   
    val cleanF = sc.clean(f)
    this.map(t => (cleanF(t), t)).groupByKey(p)
}

通过给定函数计算所得key进行分组,返回一个键值对,键为key的类型,值为Iterable,该算子会将数据打乱,即会进行shuffle。shuffle过程会进行分组,但分区数不变,即一个分区可能包含多个组,示例如下

val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
//groupBy会将数据源中的每一个数据进行分组判断,根据返回的分组key进行分组
//相同的key的值的数据会放置在一个组中
val groupRDD: RDD[(Int, Iterable[Int])] = rdd.groupBy((_: Int) % 3)
groupRDD.collect().foreach
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值