Spark Core详细文本教学02-3

本文详细介绍了Spark Core中键值对RDD的转化操作,包括reduceByKey、foldByKey、combineByKey等,并探讨了数据分组、连接和排序。同时,讲解了键值对RDD的分区方式,如Hash分区和Range分区,以及如何自定义分区。此外,还讨论了如何利用分区进行操作以提高性能,并提到了广播变量和累加器的概念及其使用方法,强调了它们在优化中的作用。
摘要由CSDN通过智能技术生成

前言

你们好我是啊晨
现在继续更新spark core spark核心。
废话不多说,内容很多选择阅读就好,很详细。
请:

三、键值对RDD

键值对 RDD 是 Spark 中许多操作所需要的常见数据类型。 本章做特别讲解。除了在基础RDD类中定义的操作之外,Spark 为包含键值对类型的 RDD 提供了一些专有的操作 在PairRDDFunctions专门进行了定义。这些 RDD 被称为 pair RDD。
有很多种方式创建pair RDD,在输入输出章节会讲解。一般如果从一个普通的RDD转 为pair RDD时,可以调用map()函数来实现,传递的函数需要返回键值对。

val pairs = lines.map(x => (x.split(" ")(0), x))

在这里插入图片描述在这里插入图片描述

1、键值对RDD的转化操作

(1)转化操作列表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(2)聚合操作

当数据集以键值对形式组织的时候,聚合具有相同键的元素进行一些统计是很常见的操 作。之前讲解过基础RDD上的fold()、combine()、reduce()等行动操作,pair RDD上则 有相应的针对键的转化操作。Spark 有一组类似的操作,可以组合具有相同键的值。这些 操作返回 RDD,因此它们是转化操作而不是行动操作。
reduceByKey() 与 reduce() 相当类似;它们都接收一个函数,并使用该函数对值进行合并。 reduceByKey() 会为数据集中的每个键进行并行的归约操作,每个归约操作会将键相同的值合 并起来。因为数据集中可能有大量的键,所以 reduceByKey() 没有被实现为向用户程序返回一 个值的行动操作。实际上,它会返回一个由各键和对应键归约出来的结果值组成的新的 RDD。
foldByKey() 则与 fold() 相当类似;它们都使用一个与 RDD 和合并函数中的数据类型相 同的零值作为初始值。与 fold() 一样,foldByKey() 操作所使用的合并函数对零值与另一 个元素进行合并,结果仍为该元素。
关于数据初始值
初始化是对每个数据进行操作,这其实是错误的。应该是针对每个partition中,每个key下的都有一个初始值。这句话怎么理解呢?看代码:
三个分区

 val rdd07 = sc.makeRDD(Array(("a",1),("a",5),("b",2),("c",3),("a",3),("b",5),("c",1),("c",3),("a",5),("a",5)),3)
    val rdd25 = rdd07.foldByKey(1)(_+_)
    rdd07.mapPartitionsWithIndex((index,items)=>Iterator(index+":"+items.mkString("、"))).collect().foreach(println(_))
    println(rdd07.collect().toBuffer)
println(rdd25.collect().toBuffer)

两个分区

 val rdd07 = sc.makeRDD(Array(("a",1),("a",5),("b",2),("c",3),("a",3),("b",5),("c",1),("c",3),("a",5),("a",5)),2)
    val rdd25 = rdd07.foldByKey(1)(_+_)
    rdd07.mapPartitionsWithIndex((index,items)=>Iterator(index+":"+items.mkString("、"))).collect().foreach(println(_))
    println(rdd07.collect().toBuffer)
    println(rdd25.collect().toBuffer)

求均值操作:版本一

input.mapValues(x => (x, 1)).reduceByKey((x, y) => (x._1 + y._1, x._2 + y._2)).map{
    case (key, value) => (key, value._1 / value._2.toFloat) }

在这里插入图片描述
combineByKey() 是最为常用的基于键进行聚合的函数。大多数基于键聚合的函数都是用它 实现的。和 aggregate() 一样,combineByKey() 可以让用户返回与输入数据的类型不同的 返回值。
要理解 combineByKey(),要先理解它在处理数据时是如何处理每个元素的。由于 combineByKey() 会遍历分区中的所有元素,因此每个元素的键要么还没有遇到过,要么就 和之前的某个元素的键相同。
如果这是一个新的元素,combineByKey() 会使用一个叫作 createCombiner() 的函数来创建 那个键对应的累加器的初始值。需要注意的是,这一过程会在每个分区中第一次出现各个 键时发生,而不是在整个 RDD 中第一次出现一个键时发生。
如果这是一个在处理当前分区之前已经遇到的键,它会使用 mergeValue() 方法将该键的累 加器对应的当前值与这个新的值进行合并。
由于每个分区都是独立处理的,因此对于同一个键可以有多个累加器。如果有两个或者更 多的分区都有对应同一个键的累加器,就需要使用用户提供的 mergeCombiners() 方法将各 个分区的结果进行合并。
求均值:版本二

val result = input.combineByKey(
  (v) => (v, 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)
).map{
    case (key, value) => (key, value._1 / value._2.toFloat) }

result.collectAsMap().map(println(_))

combineByKey是针对不同partition进行操作的。它的第一个参数用于数据初始化(后面着重讲),第二个是针对一个partition的combine操作函数,第三个是在所有partition都combine完毕后,针对所有临时结果进行combine操作的函数。
关于数据初始化
之前有人说,初始化是对每个数据进行操作,这其实是错误的。应该是针对每个partition中,每个key下的第一个数据进行操作。这句话怎么理解呢?看代码:

val rdd1 = sc.parallelize(List(1,2,2,3,3,3,3,4,4,4,4,4), 2)
val rdd2 = rdd1.map((_, 1))
val rdd3 = rdd2.combineByKey(-_, (x:Int, y:Int) => x + y, (x:Int, y:Int) => x + y)
val rdd4 = rdd2.combineByKey(+_, (x:Int, y:Int) => x + y, (x:Int, y:Int
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值