RDD(三)——transformation_value类型
map(func)
返回一个新的RDD,该RDD由每一个输入元素经过func函数转换后组成。有多少个元素,func就被执行多少次。
mapPartitions(func)
类似于map,但是,map函数是独立地在RDD的每一个分区上运行,因此在类型为T的RDD上运行时,func的函数类型必须是Iterator[T] => Iterator[U](批量地接受数据,批量地返回数据)。
def main(args: Array[String]): Unit = {
val sc: SparkContext = new SparkContext(new SparkConf()
.setMaster("local[*]").setAppName("spark")) val rawData: RDD[Int] = sc.parallelize(Array[Int](1, 2, 3)) val processedWithMap: RDD[Int] = rawData.map(_ * 2) val processedWithMappartition: RDD[Int] = rawData.mapPartitions(x => x.map(_ * 2)) processedWithMap.collect().foreach(println)
processedWithMappartition.collect().foreach(println)
}
着两个函数都能正确地返回数据处理结果:
2
4
6
map与mapPartitions函数的比较:
map函数是以元素为单位,一条一条地处理数据。mapPartitions函数是以分区为单位,一个分区一个分区地处理数据。
从线程间通信的角度来看,map函数是一条一条的交换数据,通信效率比较低;而mapPartitions函数是一个分区一个分区地交换数据,通信效率比较高,但是若分区的数据未处理完,一整个分区的数据都得不到释放,可能导致OOM问题。
mapPartitionsWithIndex(func)
类似于mapPartitions,但func带有一个整数参数表示分片的索引值,因此在类型为T的RDD上运行时,func的函数类型必须是(Int, Interator[T]) => Iterator[U];(一个是int数据类型,一个是遍历器数据类型);这个index的传入使得unc函数可以访问分区索引。
def main(args: Array[String]): Unit = { val sc: SparkContext = new SparkContext(new SparkConf()
.setMaster("local[*]").setAppName("spark")) val rdd = sc.parallelize(Array("one","two","three","four"),4) val indexRdd = rdd.mapPartitionsWithIndex((index,items)=>(items.map((index,_)))) indexRdd.foreach(println)
}
flatMap(func)
类似于map,但是每一个输入元素可以被映射为0或多个输出元素。它的函数类型是f: T => TraversableOnce[U]
def main(args: Array[String]): Unit = {
val sc: SparkContext = new SparkContext(new SparkConf()
.setMaster("local[*]").setAppName("spark")) val raw: RDD[String] = sc.parallelize(Array(("hello spark"), ("hello scala")))
val splitor: RDD[String] = raw.flatMap(_.split(" "))
splitor.collect().foreach(println);
}
打印结果为:
hello
spark
hello
scala
glom()
将每一个分区形成一个数组,形成新的RDD类型RDD[Array[T]],这个rdd中的每个元素都是一个数组类型,数组中包含的是相应分区的所有元素。
def main(args: Array[String]): Unit = {
val sc: SparkContext = new SparkContext(new SparkConf()
.setMaster("local[*]").setAppName("spark"))
val raw: RDD[Int] = sc.parallelize(1 to 16, 4)
val processed: RDD[Array[Int]] = raw.glom()
val results: Array[Array[Int]] = processed.collect()
for(result <- results){
result.foreach(print)
println()
}
}
打印结果为:
1234
5678
9101112
13141516
groupBy(func)
分组,按照传入函数的返回值进行分组。将相同的key对应的值放入一个迭代器。函数类型为f: T => K,也就是根据计算结果的不同将数据投入到不同的分区。其中有shuffle过程。
def main(args: Array[String]): Unit = { val sc: SparkContext = new SparkContext(new SparkConf().setMaster("local[*]").setAppName("spark"))
val raw: RDD[Int] = sc.parallelize(1 to 10)
val processed: RDD[(Int, Iterable[Int])] = raw.groupBy(_ % 2)
processed.saveAsTextFile("E:/idea/spark2/out/groupby")
}
分别查看两个分区文件:(0,CompactBuffer(2, 4, 6, 8, 10)) (1,CompactBuffer(1, 3, 5, 7, 9))
filter(func)
过滤。返回一个新的RDD,该RDD由经过func函数计算后返回值为true的输入元素组成。函数类型为:f: T => Boolean
问题是:该函数是否存在shuffle过程
def main(args: Array[String]): Unit = { val sc: SparkContext = new SparkContext(new SparkConf().setMaster("local[*]").setAppName("spark"))
val raw: RDD[Int] = sc.parallelize(1 to 16,4)
raw.saveAsTextFile("E:/idea/spark2/out/filter_before")
val processed: RDD[Int] = raw.filter(_ % 2 == 0)
processed.saveAsTextFile("E:/idea/spark2/out/filter_after")
}
查看文件,每个对应的分区文件在过滤之后元素变少,但是元素并没有出现跨文件的移动。据此判断filter没有shuffle过程。
sample(withReplacement, fraction, seed)
以指定的随机种子随机抽样出数量为fraction的数据,withReplacement表示是抽出的数据是否放回,true为有放回的抽样,false为无放回的抽样,seed用于指定随机数生成器种子。
def main(args: Array[String]): Unit = {
val sc: SparkContext = new SparkContext(new SparkConf()
.setMaster("local[*]").setAppName("spark"))
val raw: RDD[Int] = sc.parallelize(0 to 9)
raw.sample(true,4,3).collect().foreach(println)
println("----------")
raw.sample(true,0.4,3).collect().foreach(println)
println("----------")
raw.sample(false,0.5,3).collect().foreach(println)
println("----------")
raw.sample(false,0.5,3).collect().foreach(println)
}
}
//最后两次打印的结果是一样的;这说明,固定这三个参数,每次随机抽样的结果是一定的。
@param withReplacement can elements be sampled multiple times (replaced when sampled out)
* @param fraction expected size of the sample as a fraction of this RDD's size
* without replacement: probability that each element is chosen; fraction must be [0, 1]
* with replacement: expected number of times each element is chosen; fraction must be greater
* than or equal to 0
* @param seed seed for the random number generator
*
/*
种子:根据这个种子,结合给定的算法,会生成一个随机数序列,由seed生成A,再由A生成B,由B生成C。。。种子一定,后面的随机数也是一定的
但是这里的fraction参数如何影响样本容量。
*/
coalesce(numPartitions) 案例
缩减分区数,用于大数据集过滤后,提高小数据集的执行效率。
如何缩减:将分区中的数据简单地加以合并,因此可能会导致数据在分区间的不平衡,也就是数据倾斜。
部分函数源代码如下:
def coalesce(numPartitions: Int, shuffle: Boolean = false,
partitionCoalescer: Option[PartitionCoalescer] = Option.empty)
从中可以看出:该函数默认的shuffle机制是关闭状态,也就是简单地将一个分区的数据转移到另外一个分区。比如原先有4个分区1,2,3,4,现在将分区数缩减为2,那么1,2合并为1个分区,3,4合并为一个分区。由于没有shuffle过程的存在,转换速度快,但是可能会导致数据倾斜问题,比如,两个分区数据量比较大,合并为一个大分区,而两外两个分区数据量小,合并为一个小分区。
下面来验证这一机制,紧接着filter算子的案例:
def main(args: Array[String]): Unit = { val sc: SparkContext = new SparkContext(new SparkConf()
.setMaster("local[*]").setAppName("spark"))
val raw: RDD[Int] = sc.parallelize(1 to 16,4)
val processed: RDD[Int] = raw.filter(_ % 2 == 0)
val coalsesced: RDD[Int] = processed.coalesce(2)
coalsesced.saveAsTextFile("E:/idea/spark2/out/coalesce_afterwithshuffle")
}
filter之后,四个分区的数据依次为:2 4,6 8,10 12,14 16,
在coalesce之后,两个分区的数据依次为:2 4 6 8 ,10 12 14 16;
启动coalesce的shuffle机制:
val coalsesced: RDD[Int] = processed.coalesce(2,true)
在coalesce之后,两个分区的数据依次为:2 6 10 14,4 8 12 16;
repartition(numPartitions)
根据分区数,重新通过网络随机洗牌所有数据。
部分源代码如下:
def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T] = withScope {
coalesce(numPartitions, shuffle = true)
}
它在底层调用了coalsesce函数,并且默认开启了shuffle机制。
sortBy(func,[ascending], [numTasks])
使用func先对数据进行处理,按照处理后的数据比较结果排序,默认为正序。存在shuffle
def sortBy[K](
f: (T) => K,//根据数据,得到排序的key
ascending: Boolean = true,
numPartitions: Int = this.partitions.length)//如果没有指定分区数,采用RDD之前的分区数
示例代码如下:
def main(args: Array[String]): Unit = {
val sc: SparkContext = new SparkContext(new SparkConf()
.setMaster("local[*]").setAppName("spark"))
val raw: RDD[Int] = sc.parallelize(Array(4, 8, 7, 5, 9, 2, 1, 6, 3), 4)
val sorted: RDD[Int] = raw.sortBy(x => x, true)
sorted.saveAsTextFile("E:/idea/spark2/out/sorted")
}
各个文件中的结果为:1 2 3,4 5,6 7,8 9
双value类型指的是两个RDD的交互操作
union(otherRDD)
对源RDD和参数RDD求并集后返回一个新的RDD
subtract (otherRDD)
计算差的一种函数,去除两个RDD中相同的元素,不同的RDD将保留下来
intersection(otherRDD)
对源RDD和参数RDD求交集后返回一个新的RDD
示例代码如下:
def main(args: Array[String]): Unit = {
val sc: SparkContext = new SparkContext(new SparkConf()
.setMaster("local[*]").setAppName("spark"))
val rdd1: RDD[Int] = sc.parallelize(1 to 5)
val rdd2: RDD[Int] = sc.parallelize(3 to 8)
rdd1.union(rdd2).collect().foreach(println)
rdd1.subtract(rdd2).collect().foreach(println)
rdd1.intersection(rdd2).collect().foreach(println)
}
zip(otherRDD)
将两个RDD组合成Key/Value形式的RDD,这里默认两个RDD的partition数量以及元素数量都相同,否则会抛出异常。
演示代码如下:
def main(args: Array[String]): Unit = { val sc: SparkContext = new SparkContext(new SparkConf()
.setMaster("local[*]").setAppName("spark")) val chars: RDD[String] = sc.makeRDD(Array(("a"), ("b"), ("c"),
("d"), ("e"), ("f"), ("h"), ("i")), 2)
chars.saveAsTextFile("E:/idea/spark2/out/zip/chars") val nums: RDD[Int] = sc.makeRDD(1 to 8, 2)
nums.saveAsTextFile("E:/idea/spark2/out/zip/nums") val combines: RDD[(String, Int)] = chars.zip(nums)
combines.saveAsTextFile("E:/idea/spark2/out/combines")
}
nums分区内的数据为:1 2 3 4,5 6 7 8,
chars分区内的数据为:a b c d,e f g h,
combines分区内的数据为:(1,a)(2,b)(3,c)(4,d),(5,e)(6,f)(7,g)(8,h)
RDD(三)——transformation_value类型的更多相关文章
- Javascript权威指南——第二章词法结构,第三章类型、值和变量,第四章表达式和运算符,第五章语句
第二章 词法结构 一.HTML并不区分大小写(尽管XHTML区分大小写),而javascript区分大小写:在HTML中,这些标签和属性名可以使用大写也可以使用小写,而在javascript中必须小写 ...
- 链路层三种类型的MAC地址
若需要转载,请注明出处. 我们知道,链路层都是以MAC地址来进行通信双方的地址标识的,如下图:在应用中根据接收方的多寡来进行划分,可分为以下三种: 单播(Unicast) 多播(Multicast) ...
- 《JS权威指南学习总结--第三章类型、值和变量》
第三章 类型.值和变量 内容要点 一.数据类型 1.在编程语言中,能够表示并操作的值的类型称做数据类型 2.JS的数据类型分为两类: 原始类型:数字.字符串和布尔值 对象类型 3.JS中有两个特殊的原 ...
- matlab for循环的三种类型
学习了一半了,发现一个好网站,就是我想写这篇博客用的,网络真是个好东西!纪念下国庆啦 网址:http://www.yiibai.com/matlab/matlab_for_loop.html ---- ...
- mybatis入门系列三之类型转换器
mybatis入门系列三之类型转换器 类型转换器介绍 mybatis作为一个ORM框架,要求java中的对象与数据库中的表记录应该对应 因此java类名-数据库表名,java类属性名-数据库表字段名, ...
- C# enum、int、string三种类型互相转换
enum.int.string三种类型之间的互转 #代码: public enum Sex { Man=, Woman= } public static void enumConvert() { in ...
- { MySQL基础数据类型}一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型
MySQL基础数据类型 阅读目录 一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型 一 介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己 ...
- 缓慢变化维 (Slowly Changing Dimension) 常见的三种类型及原型设计(转)
开篇介绍 在从 OLTP 业务数据库向 DW 数据仓库抽取数据的过程中,特别是第一次导入之后的每一次增量抽取往往会遇到这样的问题:业务数据库中的一些数据发生了更改,到底要不要将这些变化也反映到数据仓库 ...
- ASP.NET 设计模式分为三种类型
设计模式分为三种类型,共23类. 一.创建型模式:单例模式.抽象工厂模式.建造者模式.工厂模式.原型模式. 二.结构型模式:适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代 ...
随机推荐
- CSS的Flex弹性布局概念
1.Flex概念: Flex是Flexible Box的缩写,顾名思义为“弹性布局”,用来为盒装模型提供最大的灵活性. 任何一个容器都可以指定为Flex 布局. 设为flex布局以后,子元素的floa ...
- Mysql 3306 被 linux 防火墙拦截
项目测试时需要本地连接linux服务器的mysql, 发现navicat无法连接 原因一:mysql没有添加外部ip的访问权限. 原因二:mysql 的 3306 端口 处于被防火墙的拦截状态. 解决 ...
- 吴裕雄--天生自然 JAVASCRIPT开发学习: 类型转换
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- mysql的常见面试问题
1.如何登陆mysql数据库 MySQL -u username -p 2.如何开启/关闭mysql服务 service mysql start/stop 3.查看mysql的状态 service m ...
- idea使用eclipse风格
说明,只是代码编辑区采用eclipse风格,其他用的是idea的IntelliJ(白色风格) 1.下载文件 2.配置
- HDU 2094产生冠军(set思维题)
Problem Description 有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛.球赛的规则如下:如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能 ...
- Fiddler 断点命令
Request 断点:bpu /priceCalculate 清除命令:bpu Response 断点:bpafter /priceCalculate 清除命令:bpafter
- 使用Matplotlib
1.Matplotlib是python的一个绘图库. 2.from matplotlib import pyplot as plt
- Python—程序设计:抽象工厂模式
抽象工厂模式 内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象. 例:生产一部手机,需要手机壳.CPU.操作系统三类对象进行组装,其中每类对象都有不同的种类.对每个具体工厂,分别生 ...
- 普通java项目转换为带有Tomcat的动态Web项目
原文链接:http://blog.csdn.net/l4432321/article/details/52049125 直接项目右键进入Properties配置,点击Project Facets,再点 ...