Spark之RDD基本操作分类

分类

Transformation(转换):

概念
将一个RDD通过一系列操作变为另一个RDD的过程,这个操作可能是简单的加减操作,也可能是某个函数或某一系列函数。

注:

  1. 所有Transformation函数都是Lazy(惰性的),不会立即执行,需要Action函数来触发
  2. Transformation操作不会触发真正的计算,只会建立RDD的关系图

Action(动作)

概念
Action操作代表依次计算的结束,返回值不是RDD,将结果返回到Driver程序或输出到外部(文件或文件夹)。

注:

  1. 所有Action函数立即执行(Eager),比如reduce、saveAsTextFile、count等。
  2. 所以Transformation只是建立计算关系,Action才是实际的执行者。
  3. 每个Action操作都会形成一个DAG调用SparkCoutext的runJob方法向集群提交请求,所以每个Action操作都对应一个DAG/Job。

Spark中的重要函数

基本函数

概述
RDD中map、filter、flatMap及foreach等函数为最基本函数,都是都RDD中每个元素进行操作,将元素传递到函数中进行转换。

  1. map函数:
  • map(f:T=>U) : RDD[T]=>RDD[U],表示将 RDD 经由某一函数 f 后,转变为另一个RDD。
  1. flatMap函数:
  • flatMap(f:T=>Seq[U]) : RDD[T]=>RDD[U]),表示将 RDD 经由某一函数 f 后,转变为一
    个新的 RDD,但是与 map 不同,RDD 中的每一个元素会被映射成新的 0 到多个元素
    (f 函数返回的是一个序列 Seq)。
  1. filter函数:
  • filter(f:T=>Bool) : RDD[T]=>RDD[T],表示将 RDD 经由某一函数 f 后,只保留 f 返回
    为 true 的数据,组成新的 RDD。
  1. foreach 函数:
  • foreach(func),将函数 func 应用在数据集的每一个元素上,通常用于更新一个累加器,
    或者和外部存储系统进行交互,例如 Redis。关于 foreach,在后续章节中还会使用,到
    时会详细介绍它的使用方法及注意事项。
  1. saveAsTextFile函数:
  • saveAsTextFile(path:String),数据集内部的元素会调用其 toString 方法,转换为字符串
    形式,然后根据传入的路径保存成文本文件,既可以是本地文件系统,也可以是HDFS 等。

分区操作函数

概述
每个RDD由多分区组成的,实际开发建议对每个分区数据的进行操作,map函数使用
mapPartitions代替、foreache函数使用foreachPartition代替。

案例(重写wordCount)
使用分区操作函数重写wordCount:

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

object RDD_分区操作 {
  def main(args: Array[String]): Unit = {
    //TODO 1.env/准备sc/SparkContext/Spark上下文执行环境
    val conf: SparkConf = new SparkConf().setAppName("wc").setMaster("local[*]");
    val sc: SparkContext = new SparkContext(conf)
    sc.setLogLevel("WARN")

    //TODO 2.source/读取数据
    //RDD:A Resilient Distributed Dataset (RDD):弹性分布式数据集,简单理解为分布式集合!使用起来和普通集合一样简单!
    //RDD[就是一行行的数据]
    val lines: RDD[String] = sc.textFile("input/words.txt")
    //获取分区数
    println(lines.getNumPartitions)
    //将一行行的数据切割成一个个单词,针对每个分区进行操作,使用迭代器迭代每个分区的数据,并进行分组聚合
    val result: RDD[(String, Int)] = lines.flatMap(_.split(" ")).mapPartitions(iter => {
      iter.map((_,1))
    }).reduceByKey(_+_)

    //遍历每个分区
    result.foreachPartition(iter =>{
      //获取分区编号
      val partitionId: Int = TaskContext.getPartitionId()
      println(s"第${partitionId}个分区:")
      iter.foreach(print(_))
      println()
    })
  }
}

重分区函数

概念
对RDD中分区的数据进行调整的函数(增加或减少函数)

增加/减少分区函数

  • 函数名称:repartition,此函数使用的谨慎,会产生Shuffle
    def repartition(numPartitions:Int)(implicit ord:Ordering[T] = null):RDD[T]

  • 函数名称:coalesce,此函数在减少RDD分区数目时不会产生Shuffle

def coalesce(
	numPartitions:Int,
	shuffle:Boolean = false,
	partitionCoalescer:Option[PartitionCoalescer] = Option.empty
)(implicit ord:Ordering[T] = null):RDD[T]
  • 函数名称:partitionBy(partitioner:Partitioner):RDD[(K,V)]
在PairRDDFunctions(此类专门针对RDD中数据类型为KeyValue对提供函数)工具类中
partitionBy函数:
//此函数通过传递分区器Partitioner改变RDD的分区数据
def patitionBy(partitioner:Partitionner):RDD[(K,V)]

注:

1. repartition的底层就是开启了Shuffle的coalesce
2. 当coalesce在参数列表中指定了Shuffle为true,也可以实现对分区数量的添加
3. coalesce在默认情况下不能实现对分区数量的增加

聚合函数

概述
在数据分析领域中,对数据聚合操作是最为关键的,在Spark框架中各个模块使用时,主要就 是其中聚合函数的使用。

分类

  1. 集合中的聚合函数
  • 函数:reduce
    def reduce[A1 > A](op:(A1,A1):A1
  • 函数:fold
    def fold[A1 > A](z:A1)(op:(A1,A1) => A1):A1
  1. RDD中的聚合函数:同列表中的聚合函数reduce和fold
  2. PairRDDFunctions聚合函数
    概述:
    在Spark中有一个object对象PairRDDFunctions,主要针对RDD的数据类型是Key/Value对的数
    据提供函数,方便数据分析处理。比如使用过的函数:reduceByKey、groupByKey等。*ByKey函 数:将相同Key的Value进行聚合操作的,省去先分组再聚合。
  • 分组函数groupByKey
    将相同Key的Value合在一起,所有的Value存储在迭代器Iterable中
    def groupByKey():RDD[(K,Iterable[V])]
    注:

此函数容易出现性能问题:

  1. 数据倾斜
    当某个Key对应的Value值非常多的时候,迭代器中的数据Value非常多
  2. OOM:内存溢出
    在Spark开发中,原则:能不适用groupByKey就不要适用,不得已而为之,可以完全不用适用
  • 分组聚合函数reduceByKey和foladByKey
// 将相同的Key的Value进行聚合操作,类似RDD中的reduce函数
def reduceBykey(func:(V,V) => V):RDD[(K,V)]

//此函数比reduceByKey多了对聚合时中间临时变量初始值,类似RDD中的fold函数
def foldBykey(zeroValue:V)(func :(V,V) => V):RDD[(K,V)]

注:

  1. 在SparkCore开发中,建议使用reduceByKey函数(它不存在分组,不会出现由于数据量过大引起的数据倾斜和内存溢出问题)
  2. reduceByKey和foldByKey聚合以后的结果类型与RDD中Value的数据类型是一样的。
  • 分组聚合函数aggregateByKey

概述:它与reduceByKey类似,但它更加灵活,可以自定义分区内和分区之间的操作,所以在企业中如果对数据聚合使用,不能使用reduceByKey完成时,考虑使用aggregateByKey函数

def aggregate[U:ClassTag]
(zeroValue:U)(
	seqOp:(U,V) => U,
	combOp:(U,U) = U
):RDD[(K,U)]

关联函数

概述
当两个RDD的数据类型为二元组Key/Value对时,可以依据Key进行关联Join。

1. 在SQL中JOIN时:
指定关联字字段 a join b on a.xxx=b.yyy

2. 在RDD数据JOIN时,要求数据类型必须是二元组(Key,Value)
根据Key进行关联的

SQL JOIN的Venn图:
在这里插入图片描述
RDD中关联JOIN函数都在PairRDDFunctions中,具体截图如下:
在这里插入图片描述
等值JOIN函数:

def join[W](other:RDD[(K,W)]):RDD[K,(V,W)]

def lefrOuterJoin[W](other:RDD[(K,W)]):RDD[(K,(V,Option[W]))]

def rightOuterJoin[W](other:RDD[(K,W)]):RDD[(K,(V,Option[W]))]
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大数据老人家i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值