上一篇里我提到可以把RDD当作一个数组,这样我们在学习spark的API时候很多问题就能很好理解了。上篇文章里的API也都是基于RDD是数组的数据模型而进行操作的。

  Spark是一个计算框架,是对mapreduce计算框架的改进,mapreduce计算框架是基于键值对也就是map的形式,之所以使用键值对是人们发现世界上大部分计算都可以使用map这样的简单计算模型进行计算。但是Spark里的计算模型却是数组形式,RDD如何处理Map的数据格式了?本篇文章就主要讲解RDD是如何处理Map的数据格式。

  Pair RDD及键值对RDD,Spark里创建Pair RDD也是可以通过两种途径,一种是从内存里读取,一种是从文件读取。

  首先是从文件读取,上篇里我们看到使用textFile方法读取文件,读取的文件是按行组织成一个数组,要让其变成map格式就的进行转化,代码如下所示:

    /*
* 测试文件数据:
* x01,1,4
x02,11,1
    x01,3,9
    x01,2,6
x02,18,12
x03,7,9
*
* */
val rddFile:RDD[(String,String)] = sc.textFile("file:///F:/sparkdata01.txt", 1).map { x => (x.split(",")(0),x.split(",")(1) + "," + x.split(",")(2)) }
val rFile:RDD[String] = rddFile.keys
println("=========createPairMap File=========")
println(rFile.collect().mkString(","))// x01,x02,x01,x01,x02,x03
println("=========createPairMap File=========")

  我们由此可以看到以读取文件方式构造RDD,我们需要使用map函数进行转化,让其变成map的形式。

  下面是通过内存方式进行创建,代码如下:

    val rdd:RDD[(String,Int)] = sc.makeRDD(List(("k01",3),("k02",6),("k03",2),("k01",26)))
val r:RDD[(String,Int)] = rdd.reduceByKey((x,y) => x + y)
println("=========createPairMap=========")
println(r.collect().mkString(","))// (k01,29),(k03,2),(k02,6)
println("=========createPairMap=========")

  RDD任然是数组形式,只不过数组的元素是("k01",3)格式是scala里面特有的Tuple2及二元组,元组可以当作一个集合,这个集合可以是各种不同数据类型组合而成,二元组就是只包含两个元素的元组。

  由此可见Pair RDD也是数组,只不过是一个元素为二元组的数组而已,上篇里对RDD的操作也是同样适用于Pair RDD的。

  下面是Pair RDD的API讲解,同样我们先说转化操作的API:

reduceByKey:合并具有相同键的值;
groupByKey:对具有相同键的值进行分组;
keys:返回一个仅包含键值的RDD;
values:返回一个仅包含值的RDD;
sortByKey:返回一个根据键值排序的RDD;
flatMapValues:针对Pair RDD中的每个值应用一个返回迭代器的函数,然后对返回的每个元素都生成一个对应原键的键值对记录;
mapValues:对Pair RDD里每一个值应用一个函数,但是不会对键值进行操作;
combineByKey:使用不同的返回类型合并具有相同键的值;
subtractByKey:操作的RDD我们命名为RDD1,参数RDD命名为参数RDD,剔除掉RDD1里和参数RDD中键相同的元素;
join:对两个RDD进行内连接;
rightOuterJoin:对两个RDD进行连接操作,第一个RDD的键必须存在,第二个RDD的键不再第一个RDD里面有那么就会被剔除掉,相同键的值会被合并;
leftOuterJoin:对两个RDD进行连接操作,第二个RDD的键必须存在,第一个RDD的键不再第二个RDD里面有那么就会被剔除掉,相同键的值会被合并;
cogroup:将两个RDD里相同键的数据分组在一起

  下面就是行动操作的API了,具体如下:

countByKey:对每个键的元素进行分别计数;
collectAsMap:将结果变成一个map;
lookup:在RDD里使用键值查找数据

  接下来我再提提那些不是很常用的RDD操作,具体如下:

  转化操作的:

sample:对RDD采样;

  行动操作:

take(num):返回RDD里num个元素,随机的;
top(num):返回RDD里最前面的num个元素,这个方法实用性还比较高;
takeSample:从RDD里返回任意一些元素;
sample:对RDD里的数据采样;
takeOrdered:从RDD里按照提供的顺序返回最前面的num个元素

  接下来就是示例代码了,如下所示:

package cn.com.sparktest

import org.apache.spark.SparkConf
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.SparkContext._
import org.apache.spark.rdd.RDD
import org.apache.spark.util.collection.CompactBuffer object SparkPairMap { val conf:SparkConf = new SparkConf().setAppName("spark pair map").setMaster("local[2]")
val sc:SparkContext = new SparkContext(conf) /**
* 构建Pair RDD
*/
def createPairMap():Unit = {
val rdd:RDD[(String,Int)] = sc.makeRDD(List(("k01",3),("k02",6),("k03",2),("k01",26)))
val r:RDD[(String,Int)] = rdd.reduceByKey((x,y) => x + y)
println("=========createPairMap=========")
println(r.collect().mkString(","))// (k01,29),(k03,2),(k02,6)
println("=========createPairMap=========") /*
* 测试文件数据:
* x01,1,4
x02,11,1
x01,3,9
x01,2,6
x02,18,12
x03,7,9
*
* */
val rddFile:RDD[(String,String)] = sc.textFile("file:///F:/sparkdata01.txt", 1).map { x => (x.split(",")(0),x.split(",")(1) + "," + x.split(",")(2)) }
val rFile:RDD[String] = rddFile.keys
println("=========createPairMap File=========")
println(rFile.collect().mkString(","))// x01,x02,x01,x01,x02,x03
println("=========createPairMap File=========")
} /**
* 关于Pair RDD的转化操作和行动操作
*/
def pairMapRDD(path:String):Unit = {
val rdd:RDD[(String,Int)] = sc.makeRDD(List(("k01",3),("k02",6),("k03",2),("k01",26)))
val other:RDD[(String,Int)] = sc.parallelize(List(("k01",29)), 1) // 转化操作
val rddReduce:RDD[(String,Int)] = rdd.reduceByKey((x,y) => x + y)
println("====reduceByKey===:" + rddReduce.collect().mkString(","))// (k01,29),(k03,2),(k02,6)
val rddGroup:RDD[(String,Iterable[Int])] = rdd.groupByKey()
println("====groupByKey===:" + rddGroup.collect().mkString(","))// (k01,CompactBuffer(3, 26)),(k03,CompactBuffer(2)),(k02,CompactBuffer(6))
val rddKeys:RDD[String] = rdd.keys
println("====keys=====:" + rddKeys.collect().mkString(","))// k01,k02,k03,k01
val rddVals:RDD[Int] = rdd.values
println("======values===:" + rddVals.collect().mkString(","))// 3,6,2,26
val rddSortAsc:RDD[(String,Int)] = rdd.sortByKey(true, 1)
val rddSortDes:RDD[(String,Int)] = rdd.sortByKey(false, 1)
println("====rddSortAsc=====:" + rddSortAsc.collect().mkString(","))// (k01,3),(k01,26),(k02,6),(k03,2)
println("======rddSortDes=====:" + rddSortDes.collect().mkString(","))// (k03,2),(k02,6),(k01,3),(k01,26)
val rddFmVal:RDD[(String,Int)] = rdd.flatMapValues { x => List(x + 10) }
println("====flatMapValues===:" + rddFmVal.collect().mkString(","))// (k01,13),(k02,16),(k03,12),(k01,36)
val rddMapVal:RDD[(String,Int)] = rdd.mapValues { x => x + 10 }
println("====mapValues====:" + rddMapVal.collect().mkString(","))// (k01,13),(k02,16),(k03,12),(k01,36)
val rddCombine:RDD[(String,(Int,Int))] = rdd.combineByKey(x => (x,1), (param:(Int,Int),x) => (param._1 + x,param._2 + 1), (p1:(Int,Int),p2:(Int,Int)) => (p1._1 + p2._1,p1._2 + p2._2))
println("====combineByKey====:" + rddCombine.collect().mkString(","))//(k01,(29,2)),(k03,(2,1)),(k02,(6,1))
val rddSubtract:RDD[(String,Int)] = rdd.subtractByKey(other);
println("====subtractByKey====:" + rddSubtract.collect().mkString(","))// (k03,2),(k02,6)
val rddJoin:RDD[(String,(Int,Int))] = rdd.join(other)
println("=====rddJoin====:" + rddJoin.collect().mkString(","))// (k01,(3,29)),(k01,(26,29))
val rddRight:RDD[(String,(Option[Int],Int))] = rdd.rightOuterJoin(other)
println("====rightOuterJoin=====:" + rddRight.collect().mkString(","))// (k01,(Some(3),29)),(k01,(Some(26),29))
val rddLeft:RDD[(String,(Int,Option[Int]))] = rdd.leftOuterJoin(other)
println("=====rddLeft=====:" + rddLeft.collect().mkString(","))// (k01,(3,Some(29))),(k01,(26,Some(29))),(k03,(2,None)),(k02,(6,None))
val rddCogroup: RDD[(String, (Iterable[Int], Iterable[Int]))] = rdd.cogroup(other)
println("=====cogroup=====:" + rddCogroup.collect().mkString(","))// (k01,(CompactBuffer(3, 26),CompactBuffer(29))),(k03,(CompactBuffer(2),CompactBuffer())),(k02,(CompactBuffer(6),CompactBuffer())) // 行动操作
val resCountByKey = rdd.countByKey()
println("=====countByKey=====:" + resCountByKey)// Map(k01 -> 2, k03 -> 1, k02 -> 1)
val resColMap = rdd.collectAsMap()
println("=====resColMap=====:" + resColMap)//Map(k02 -> 6, k01 -> 26, k03 -> 2)
val resLookup = rdd.lookup("k01")
println("====lookup===:" + resLookup) // WrappedArray(3, 26)
} /**
* 其他一些不常用的RDD操作
*/
def otherRDDOperate(){
val rdd:RDD[(String,Int)] = sc.makeRDD(List(("k01",3),("k02",6),("k03",2),("k01",26))) println("=====first=====:" + rdd.first())//(k01,3)
val resTop = rdd.top(2).map(x => x._1 + ";" + x._2)
println("=====top=====:" + resTop.mkString(","))// k03;2,k02;6
val resTake = rdd.take(2).map(x => x._1 + ";" + x._2)
println("=======take====:" + resTake.mkString(","))// k01;3,k02;6
val resTakeSample = rdd.takeSample(false, 2).map(x => x._1 + ";" + x._2)
println("=====takeSample====:" + resTakeSample.mkString(","))// k01;26,k03;2
val resSample1 = rdd.sample(false, 0.25)
val resSample2 = rdd.sample(false, 0.75)
val resSample3 = rdd.sample(false, 0.5)
println("=====sample======:" + resSample1.collect().mkString(","))// 无
println("=====sample======:" + resSample2.collect().mkString(","))// (k01,3),(k02,6),(k01,26)
println("=====sample======:" + resSample3.collect().mkString(","))// (k01,3),(k01,26)
} def main(args: Array[String]): Unit = {
createPairMap()
pairMapRDD("file:///F:/sparkdata01.txt")
otherRDDOperate()
} }

  本篇到此就将我知道的spark的API全部讲完了,两篇文章里的示例代码都是经过测试的,可以直接运行,大家在阅读代码时候最好注意这个特点:我在写RDD转化代码时候都是很明确的写上了转化后的RDD的数据类型,这样做的目的就是让读者更加清晰的认识不同RDD转化后的数据类型,这点在实际开发里非常重要,在实际的计算里我们经常会不同的计算算法不停的转化RDD的数据类型,而使用scala开发spark程序时候,我发现scala和javascript很类似,我们不去指定返回值数据类型,scala编译器也会自动推算结果的数据类型,因此编码时候我们可以不指定具体数据类型。这个特点就会让我们在实际开发里碰到种种问题,因此我在示例代码里明确了RDD转化后的数据类型。

  在使用Pair RDD时候,我们要引入:

import org.apache.spark.SparkContext._

  否则代码就有可能报错,说找不到对应的方法,这个引入就是scala里导入的隐世类型转化的功能,原理和上段文字说到的内容差不多。

开发spark程序不仅仅只可以使用scala,还可以使用python,java,不过scala使用起来更加方便,spark的API简单清晰,这样的编程大大降低了原先使用mapreduce编程的难度,但是如果我们要深入掌握这些API那么就要更加深入的学习下scala。下一篇我就根据spark里RDD的API讲解一些scala的语法,通过这些语法让我们更好的掌握Spark的API。

Spark笔记:RDD基本操作(下)的更多相关文章

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

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

  2. Spark笔记:RDD基本操作(上)

    本文主要是讲解spark里RDD的基础操作.RDD是spark特有的数据模型,谈到RDD就会提到什么弹性分布式数据集,什么有向无环图,本文暂时不去展开这些高深概念,在阅读本文时候,大家可以就把RDD当 ...

  3. Spark RDD/Core 编程 API入门系列 之rdd实战(rdd基本操作实战及transformation和action流程图)(源码)(三)

    本博文的主要内容是: 1.rdd基本操作实战 2.transformation和action流程图 3.典型的transformation和action RDD有3种操作: 1.  Trandform ...

  4. Spark学习笔记——RDD编程

    1.RDD——弹性分布式数据集(Resilient Distributed Dataset) RDD是一个分布式的元素集合,在Spark中,对数据的操作就是创建RDD.转换已有的RDD和调用RDD操作 ...

  5. Spark 基础及RDD基本操作

    什么是RDD RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变.可分区.里面的元素可并行计算的集合.RDD具有数据 ...

  6. 关于Spark中RDD的设计的一些分析

    RDD, Resilient Distributed Dataset,弹性分布式数据集, 是Spark的核心概念. 对于RDD的原理性的知识,可以参阅Resilient Distributed Dat ...

  7. 解读Spark Streaming RDD的全生命周期

    本节主要内容: 一.DStream与RDD关系的彻底的研究 二.StreamingRDD的生成彻底研究 Spark Streaming RDD思考三个关键的问题: RDD本身是基本对象,根据一定时间定 ...

  8. spark笔记 环境配置

    spark笔记 spark简介 saprk 有六个核心组件: SparkCore.SparkSQL.SparkStreaming.StructedStreaming.MLlib,Graphx Spar ...

  9. [Spark] Spark的RDD编程

    本篇博客中的操作都在 ./bin/pyspark 中执行. RDD,即弹性分布式数据集(Resilient Distributed Dataset),是Spark对数据的核心抽象.RDD是分布式元素的 ...

随机推荐

  1. 从Membership 到 .NET4.5 之 ASP.NET Identity

    我们前面已经讨论过了如何在一个网站中集成最基本的Membership功能,然后深入学习了Membership的架构设计.正所谓从实践从来,到实践从去,在我们把Membership的结构吃透之后,我们要 ...

  2. ExtJS 4.2 业务开发(二)数据展示和查询

    本篇开始模拟一个船舶管理系统,提供查询.添加.修改船舶的功能,这里介绍其中的数据展示和查询功能. 目录 1. 数据展示 2. 数据查询 3. 在线演示 1. 数据展示 在这里我们将模拟一个船舶管理系统 ...

  3. Linux下Nodejs安装(完整详细)

    之前安装过windows下以及Mac下的node,感觉还是很方便的,不成想今天安装linux下的坑了老半天,特此记录. 首先去官网下载代码,这里一定要注意安装分两种,一种是Source Code源码, ...

  4. python开发环境搭建

    虽然网上有很多python开发环境搭建的文章,不过重复造轮子还是要的,记录一下过程,方便自己以后配置,也方便正在学习中的同事配置他们的环境. 1.准备好安装包 1)上python官网下载python运 ...

  5. LeetCode 7. Reverse Integer

    Reverse digits of an integer. Example1: x = 123, return 321 Example2: x = -123, return -321 Have you ...

  6. [.NET] C# 知识回顾 - Event 事件

    C# 知识回顾 - Event 事件 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6060297.html 序 昨天,通过<C# 知识回顾 - ...

  7. H5坦克大战之【玩家控制坦克移动2】

    周一没有看圣诞大战,这几天比较忙也没有看赛后的报道,今天就先不扯NBA,随便扯扯自己.昨天在电脑里找东西的时候翻到以前兼职健身教练时的照片,思绪一下子回到学生时代,脑子久久换不过来.现在深深觉得健身和 ...

  8. 使用C/C++写Python模块

    最近看开源项目时学习了一下用C/C++写python模块,顺便把学习进行一下总结,废话少说直接开始: 环境:windows.python2.78.VS2010或MingW 1 创建VC工程 (1) 打 ...

  9. IIC驱动移植在linux3.14.78上的实现和在linux2.6.29上实现对比(deep dive)

    首先说明下为什么写这篇文章,网上有许多博客也是介绍I2C驱动在linux上移植的实现,但是笔者认为他们相当一部分没有分清所写的驱动时的驱动模型,是基于device tree, 还是基于传统的Platf ...

  10. android Handler介绍

    Handler使用介绍: Handler根据接收的消息,处理UI更新.Thread线程发出消息,通知Handler更新UI. Handler mHandler = new Handler() {  p ...