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类型的更多相关文章

  1. Javascript权威指南——第二章词法结构,第三章类型、值和变量,第四章表达式和运算符,第五章语句

    第二章 词法结构 一.HTML并不区分大小写(尽管XHTML区分大小写),而javascript区分大小写:在HTML中,这些标签和属性名可以使用大写也可以使用小写,而在javascript中必须小写 ...

  2. 链路层三种类型的MAC地址

    若需要转载,请注明出处. 我们知道,链路层都是以MAC地址来进行通信双方的地址标识的,如下图:在应用中根据接收方的多寡来进行划分,可分为以下三种: 单播(Unicast) 多播(Multicast) ...

  3. 《JS权威指南学习总结--第三章类型、值和变量》

    第三章 类型.值和变量 内容要点 一.数据类型 1.在编程语言中,能够表示并操作的值的类型称做数据类型 2.JS的数据类型分为两类: 原始类型:数字.字符串和布尔值 对象类型 3.JS中有两个特殊的原 ...

  4. matlab for循环的三种类型

    学习了一半了,发现一个好网站,就是我想写这篇博客用的,网络真是个好东西!纪念下国庆啦 网址:http://www.yiibai.com/matlab/matlab_for_loop.html ---- ...

  5. mybatis入门系列三之类型转换器

    mybatis入门系列三之类型转换器 类型转换器介绍 mybatis作为一个ORM框架,要求java中的对象与数据库中的表记录应该对应 因此java类名-数据库表名,java类属性名-数据库表字段名, ...

  6. C# enum、int、string三种类型互相转换

    enum.int.string三种类型之间的互转 #代码: public enum Sex { Man=, Woman= } public static void enumConvert() { in ...

  7. { MySQL基础数据类型}一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型

    MySQL基础数据类型 阅读目录 一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型 一 介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己 ...

  8. 缓慢变化维 (Slowly Changing Dimension) 常见的三种类型及原型设计(转)

    开篇介绍 在从 OLTP 业务数据库向 DW 数据仓库抽取数据的过程中,特别是第一次导入之后的每一次增量抽取往往会遇到这样的问题:业务数据库中的一些数据发生了更改,到底要不要将这些变化也反映到数据仓库 ...

  9. ASP.NET 设计模式分为三种类型

    设计模式分为三种类型,共23类.  一.创建型模式:单例模式.抽象工厂模式.建造者模式.工厂模式.原型模式.      二.结构型模式:适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代 ...

随机推荐

  1. python安装wordcloud、jieba,pyecharts

    1.安装wordcloud: 适用于无法使用pip install wordcloud安装的情况: 据python和windows 版本 到https://www.lfd.uci.edu/~gohlk ...

  2. nginx重写常用写法

    1.将http协议重写成https协议: (用户用http进行访问,但后端是https),则可添加80 http端口监听,然后进行https rewrite; server {     listen ...

  3. SeetaFaceQt:Qt多线程

    为什么要做多线程,说个最简单的道理就是我们不希望在软件处理数据的时候界面处于无法响应的假死状态.有些处理是灰常花时间的,如果把这样的处理放到主线程中执行,就会导致软件一条路走到底,要等到处理完才能接收 ...

  4. Python中Opencv和PIL.Image读取图片的差异对比

    近日,在进行深度学习进行推理的时候,发现不管怎么样都得不出正确的结果,再仔细和正确的代码进行对比了后发现原来是Python中不同的库读取的图片数组是有差异的. image = np.array(Ima ...

  5. Spring原理系列一:Spring Bean的生命周期

    一.前言 在日常开发中,spring极大地简化了我们日常的开发工作.spring为我们管理好bean, 我们拿来就用.但是我们不应该只停留在使用层面,深究spring内部的原理,才能在使用时融汇贯通. ...

  6. 委托、Action、Func使用

    参考 using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syste ...

  7. 吴裕雄--天生自然 JAVASCRIPT开发学习: 错误 - throw、try 和 catch

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  8. java 实现递归实现tree(2)

    import com.google.common.collect.Lists; import org.springframework.cglib.beans.BeanCopier; import ja ...

  9. 下面介绍mysql中模糊查询的四种用法:

    下面介绍mysql中模糊查询的四种用法: 1,%:表示任意0个或多个字符.可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示. 比如 SELECT * FROM [user] ...

  10. Java 工厂模式登陆系统实现

    没有工厂模式 设定一个登陆系统 UserServiceImp.java public class UserServiceImp { public boolean login(String userna ...