本文参考

参考《Spark快速大数据分析》动物书中的第四章"键值对操作",由于pair RDD的一些特殊操作,没有和前面两篇的API归纳放在一起做示例

前面的几个api —— reduceByKey()函数、foldByKey()函数、groupByKey()函数、combineByKey()函数、mapValues()函数、flatMapValues()函数、keys()函数、values()函数和sortByKey函数是针对一个Pair RDD的操作

而后的几个api —— subtractByKey()函数、join()函数、rightOuterJoin()函数、leftOuterJoin()函数和cogroup()函数是针对两个Pair RDD的函数

Spark转化操作API归纳:https://www.cnblogs.com/kuluo/p/12545374.html

Spark行动操作API归纳:https://www.cnblogs.com/kuluo/p/12550938.html

Pair RDD行动操作API归纳:https://www.cnblogs.com/kuluo/p/12567221.html

环境

idea + spark 2.4.5 + scala 2.11.12

RDD均通过SparkContext的parallelize()函数创建

reduceByKey()函数

目的:

合并具有相同键的值,在经典的WordCount示例程序里,通过该函数合并相同字母(键)的出现次数(值)

代码:

val testList = List("a a a b b b", "b b c c c", "c d d")
val testRdd = sc.parallelize(testList)
testRdd.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _).foreach(pair => print(s"$pair "))

输出:

(d,2) (a,3) (b,5) (c,4)

foldByKey()函数

目的:

合并具有相同键的值,同reduceByKey()类似,不过要指定初始值

代码:

val testList = List("a a a b b b", "b b c c c", "c d d")
val testRdd = sc.parallelize(testList)
testRdd.flatMap(_.split(" ")).map((_, 1)).foldByKey(0)(_ + _).foreach(pair => print(s"$pair "))

输出:

(d,2) (a,3) (b,5) (c,4)

mapValues()函数

目的:

对pair RDD中的每个值应用一个函数而不改变键

代码:

val testList = List("a a a b b b", "b b c c c", "c d d")
val testRdd = sc.parallelize(testList)
testRdd.flatMap(_.split(" ")).map((_, 1))
.reduceByKey(_ + _)
.mapValues(_ * 2)
.foreach(pair => print(s"$pair "))

输出:

(d,4) (a,6) (b,10) (c,8)

flatMapValues()函数

目的:

对pair RDD中的每个值应用一个返回迭代器的函数,然后对返回的每个元素都生成一个对应原键的键值对记录

代码:

val testList = List("a a a b b b", "b b c c c", "c d d")
val testRdd = sc.parallelize(testList)
testRdd.flatMap(_.split(" ")).map((_, 1))
.reduceByKey(_ + _)
.flatMapValues(_ to 5)
.foreach(pair => print(s"$pair "))

输出:

(d,2) (d,3) (d,4) (d,5) (a,3) (a,4) (a,5) (b,5) (c,4) (c,5)

groupByKey()函数

目的:

对具有相同键的值进行分组

代码:

val testList = List("a a a b b b", "b b c c c", "c d d")
val testRdd = sc.parallelize(testList)
testRdd.flatMap(_.split(" ")).map((_, 1))
.groupByKey()

/**
* (d,CompactBuffer(1, 1)) (a,CompactBuffer(1, 1, 1)) (b,CompactBuffer(1, 1, 1, 1, 1)) (c,CompactBuffer(1, 1, 1, 1))
*/

.mapValues(_.sum)
.foreach(pair => print(s"$pair "))

输出:

使用groupByKey()函数后,直接输出的结果为

(d,CompactBuffer(1, 1)) (a,CompactBuffer(1, 1, 1)) (b,CompactBuffer(1, 1, 1, 1, 1)) (c,CompactBuffer(1, 1, 1, 1))

在groupByKey()函数后使用mapValues()函数,可以实现和WordCount的reduceByKey()函数相同的效果,输出的结果为

(d,2) (a,3) (b,5) (c,4)

更高效的操作:

可以一步到位的reduceByKey()函数效率更高,避免使用groupByKey()函数分步操作,以下为源码注释

This operation may be very expensive. If you are grouping in order to perform an aggregation (such as a sum or average) over each key, using `PairRDDFunctions.aggregateByKey` or `PairRDDFunctions.reduceByKey` will provide much better performance.

combineByKey()函数

目的:

使用不同的返回类型合并具有相同键的值,大多数基于键聚合的函数都是用它实现的(如reduceByKey()函数和foldByKey()函数)

遇到一个新元素时,会使用createCombiner()的函数来创建那个键对应的累加器的初始值,这一过程会在每个分区中第一次出现各个键时发生,而不是在整个RDD中第一次出现时发生

若是一个之前遇到过的键,会使用mergeValue()的函数将该键的累加器对应的当前值与这个新的值进行合并

每个分区独立处理,对于同一个键可以有多个累加器,若有多个分区对应同一个键的累加器,会使用mergeCombiners()函数将各个分区的结果进行合并

代码(WordCount):

val testList = List("a a a b b b", "b b c c c", "c d d")
val testRdd = sc.parallelize(testList)
testRdd.flatMap(_.split(" ")).map((_, 1))
.combineByKey(x => x,
(x:Int, y:Int) => x + y,
(x:Int, y:Int) => x + y)
.foreach(pair => print(s"$pair "))

输出:

(d,2) (a,3) (b,5) (c,4)

代码(求平均):

/*
* (a,3) (b,5) (c,4) (d,2)
*/
val
testList1 = List("a a a b b b", "b b c c c", "c d d")
/*
* (a,5) (b,4) (c,6)
*/
val
testList2 = List("a a a a a b b", "b b c c c c c", "c")

val testRdd1 = sc.parallelize(testList1)
val testRdd2 = sc.parallelize(testList2)

/*
* union
取并集,构造(a,3) (a,5) (b,5) (b,4) (c,4) (c,6) (d,2)
*/
val
testRdd3 = testRdd1.flatMap(_.split(" ")).map((_, 1))
.combineByKey(x => x,
(x: Int, y: Int) => x + y,
(x: Int, y: Int) => x + y)
.union(

testRdd2.flatMap(_.split(" ")).map((_, 1))
.combineByKey(x => x,
(x: Int, y: Int) => x + y,
(x: Int, y: Int) => x + y)
)

testRdd3.combineByKey(

x => (x, 1),
(x: (Int, Int), y) => (x._1 + y, x._2 + 1),
(x: (Int, Int), y: (Int, Int)) => (x._1 + y._1, x._2 + y._2)
).mapValues(value => 1.0 * value._1 / value._2).foreach(pair => print(s"$pair "))

输出:

(d,2.0) (a,4.0) (b,4.5) (c,5.0)

keys()函数

目的:

返回一个仅包含键的RDD

代码:

val testList = List("a a a b b b", "b b c c c", "c d d")
val testRdd = sc.parallelize(testList)
testRdd.flatMap(_.split(" ")).map((_, 1))
.reduceByKey(_ + _)
.keys

.foreach(key => print(s"$key "))

输出:

d a b c

values()函数

目的:

返回一个仅包含值得RDD

代码:

val testList = List("a a a b b b", "b b c c c", "c d d")
val testRdd = sc.parallelize(testList)
testRdd.flatMap(_.split(" ")).map((_, 1))
.reduceByKey(_ + _)
.values

.foreach(value => print(s"$value "))

输出:

2 3 5 4

sortByKey()函数

目的:

返回一个根据键排序的RDD,默认升序

代码:

val testList = List("a a a b b b", "b b c c c", "c d d")
val testRdd = sc.parallelize(testList)
testRdd.flatMap(_.split(" ")).map((_, 1))
.reduceByKey(_ + _)
.sortByKey(false)
.foreach(pair => print(s"$pair "))

输出:

(d,2) (c,4) (b,5) (a,3)

subtractByKey()函数

目的:

类似于集合中的差集,删掉当前RDD中键与另一个RDD中的键相同的元素

代码:

/*
* (a,3) (b,5) (c,4) (d,2)
*/
val
testList1 = List("a a a b b b", "b b c c c", "c d d")
/*
* (a,5) (b,4) (c,6)
*/
val
testList2 = List("a a a a a b b", "b b c c c c c", "c")

val testRdd1 = sc.parallelize(testList1)
val testRdd2 = sc.parallelize(testList2)

testRdd1.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
.subtractByKey(testRdd2.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _))
.foreach(pair => print(s"$pair "))

输出:

(d,2)

join()函数

目的:

类似于集合中的并集,对两个RDD进行内连接

代码:

/*
* (a,3) (b,5) (c,4) (d,2)
*/
val
testList1 = List("a a a b b b", "b b c c c", "c d d")
/*
* (a,5) (b,4) (c,6)
*/
val
testList2 = List("a a a a a b b", "b b c c c c c", "c")

val testRdd1 = sc.parallelize(testList1)
val testRdd2 = sc.parallelize(testList2)

testRdd1.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
.join(testRdd2.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _))
.foreach(pair => print(s"$pair "))

输出:

(a,(3,5)) (b,(5,4)) (c,(4,6))

rightOuterJoin()函数

目的:

类似于集合的右连接,确保函数内的RDD的键存在

代码:

/*
* (a,3) (b,5) (c,4) (d,2)
*/
val
testList1 = List("a a a b b b", "b b c c c", "c d d")
/*
* (a,5) (b,4) (c,6)
*/
val
testList2 = List("a a a a a b b", "b b c c c c c", "c")

val testRdd1 = sc.parallelize(testList1)
val testRdd2 = sc.parallelize(testList2)

testRdd1.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
.rightOuterJoin(testRdd2.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _))
.foreach(pair => print(s"$pair "))

输出:

(a,(Some(3),5)) (b,(Some(5),4)) (c,(Some(4),6))

leftOuterJoin()函数

目的:

类似于集合的左连接,确保调用该函数的RDD的键存在

代码:

/*
* (a,3) (b,5) (c,4) (d,2)
*/
val
testList1 = List("a a a b b b", "b b c c c", "c d d")
/*
* (a,5) (b,4) (c,6)
*/
val
testList2 = List("a a a a a b b", "b b c c c c c", "c")

val testRdd1 = sc.parallelize(testList1)
val testRdd2 = sc.parallelize(testList2)

testRdd1.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
.leftOuterJoin(testRdd2.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _))
.foreach(pair => print(s"$pair "))

输出:

(d,(2,None)) (a,(3,Some(5))) (b,(5,Some(4))) (c,(4,Some(6)))

cogroup()函数

目的:

将两个RDD中拥有相同键的数据分组到一起

代码:

/*
* (a,3) (b,5) (c,4) (d,2)
*/
val
testList1 = List("a a a b b b", "b b c c c", "c d d")
/*
* (a,5) (b,4) (c,6)
*/
val
testList2 = List("a a a a a b b", "b b c c c c c", "c")

val testRdd1 = sc.parallelize(testList1)
val testRdd2 = sc.parallelize(testList2)

testRdd1.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
.cogroup(testRdd2.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _))
.foreach(pair => print(s"$pair "))

输出:

(d,(CompactBuffer(2),CompactBuffer())) (a,(CompactBuffer(3),CompactBuffer(5)))

(b,(CompactBuffer(5),CompactBuffer(4))) (c,(CompactBuffer(4),CompactBuffer(6)))

Spark学习摘记 —— Pair RDD转化操作API归纳的更多相关文章

  1. Spark学习摘记 —— Pair RDD行动操作API归纳

    本文参考 参考<Spark快速大数据分析>动物书中的第四章"键值对操作",本篇是对RDD转化操作和行动操作API归纳的最后一篇 RDD转化操作API归纳:https:/ ...

  2. Spark学习摘记 —— RDD转化操作API归纳

    本文参考 在阅读了<Spark快速大数据分析>动物书后,大概了解到了spark常用的api,不过书中并没有给予所有api具体的示例,而且现在spark的最新版本已经上升到了2.4.5,动物 ...

  3. Spark学习摘记 —— RDD行动操作API归纳

    本文参考 参考<Spark快速大数据分析>动物书中的第三章"RDD编程",前一篇文章已经概述了转化操作相关的API,本文再介绍行动操作API 和转化操作API不同的是, ...

  4. Spark学习之键值对(pair RDD)操作(3)

    Spark学习之键值对(pair RDD)操作(3) 1. 我们通常从一个RDD中提取某些字段(如代表事件时间.用户ID或者其他标识符的字段),并使用这些字段为pair RDD操作中的键. 2. 创建 ...

  5. spark中的pair rdd,看这一篇就够了

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是spark专题的第四篇文章,我们一起来看下Pair RDD. 定义 在之前的文章当中,我们已经熟悉了RDD的相关概念,也了解了RDD基 ...

  6. Spark学习笔记3——RDD(下)

    目录 Spark学习笔记3--RDD(下) 向Spark传递函数 通过匿名内部类 通过具名类传递 通过带参数的 Java 函数类传递 通过 lambda 表达式传递(仅限于 Java 8 及以上) 常 ...

  7. Spark学习笔记2——RDD(上)

    目录 Spark学习笔记2--RDD(上) RDD是什么? 例子 创建 RDD 并行化方式 读取外部数据集方式 RDD 操作 转化操作 行动操作 惰性求值 Spark学习笔记2--RDD(上) 笔记摘 ...

  8. spark Pair RDD 基础操作

    下面是Pair RDD的API讲解 转化操作 reduceByKey:合并具有相同键的值: groupByKey:对具有相同键的值进行分组: keys:返回一个仅包含键值的RDD: values:返回 ...

  9. Spark学习之键值对操作总结

    键值对 RDD 是 Spark 中许多操作所需要的常见数据类型.键值对 RDD 通常用来进行聚合计算.我们一般要先通过一些初始 ETL(抽取.转化.装载)操作来将数据转化为键值对形式.键值对 RDD ...

随机推荐

  1. HDFS成员的工作机制

    NameNode工作机制 nn负责管理块的元数据信息,元数据信息为fsimage和edits预写日志,通过edits预写日志来更新fsimage中的元数据信息,每次namenode启动时,都会将磁盘中 ...

  2. (二)ECMA 335 解析 /ECMA 334

    C#被ECMA组织,定义为了<ECMA334>标准化语言. 什么概念? 比如说,上一次成为ECMA标准的语言是Javascript.即<ECMA262>标准. <ECMA ...

  3. 【C# 基础概念】命名空间

    命名空间 C#10 新功能==================== 命名空间格式:声明所有后续声明都是已声明的命名空间的成员: //C#10 命名空间的新写法,这种方式一个文件只能有一个命名空间. / ...

  4. 解构函数(Deconstruct)

    元组的解构是C#内置支持的. var countrInfo = ("Malawi", "Lilongwe", io); (string name, string ...

  5. omnet++:cMessage、cSimpleModule、cGate

    cMessage Message可以被调度(self-message).取消.从一个Gate发送出去.直接发给另一个module:所有以上,都是通过cSimpleModule来实现的. Message ...

  6. hexo部署到github时,提示typeError [ERR_INVALID_ARG_TYPE] The “mode“ argument must be integer. Receive

    hexo部署到github时,提示typeError [ERR_INVALID_ARG_TYPE]: The "mode" argument must be integer. Re ...

  7. VirtualBox虚拟机--桥接模式

    问题概述:VirtualBox虚拟机设置桥接模式,与宿主机互相ping通. 注:如果按照以下方式设置了还是ping不通,查看虚拟机防火墙是否已关. 公司电脑拿去维修了,在自己家里电脑上部署项目开发环境 ...

  8. EasySwoole-延迟队列-取消订单

    场景: 在用户要支付订单的时候,如果超过30分钟未支付,会把订单关掉.当然我们可以做一个定时任务,每个一段时间来扫描未支付的订单, 如果该订单超过支付时间就关闭,但是在数据量小的时候并没有什么大的问题 ...

  9. kkFileView对接svn服务完成文件在线预览功能

    1.需求: 之前在公司内部搭建了svn服务器,给部门存放文档.视频,做成了一个文档服务器来用,随着视频文件太大,每次下载太慢 需要把文件在线打开查看 2.解决: kkFileView https:// ...

  10. [差分数组] LeetCode789 得分最高的最小轮调

    LeetCode 得分最高的最小轮调 今天当然CV了因为今天比较忙,所以直接走算法,因为什么都不做的话并不符合社会主义核心价值观,今天小学一手查分数组. 题目:并不存在CV了还写什么题解 算法背景: ...