Spark函数详解系列之RDD基本转换

摘要:

RDD:弹性分布式数据集,是一种特殊集合‚ 支持多种来源‚ 有容错机制‚ 可以被缓存‚ 支持并行操作,一个RDD代表一个分区里的数据集

RDD有两种操作算子:

Transformation(转换):Transformation属于延迟计算,当一个RDD转换成另一个RDD时并没有立即进行转换,仅仅是记住了数据集的逻辑操作

Ation(执行):触发Spark作业的运行,真正触发转换算子的计算

本系列主要讲解Spark中常用的函数操作:

1.RDD基本转换

2.键-值RDD转换

3.Action操作篇

1.map(func):数据集中的每个元素经过用户自定义的函数转换形成一个新的RDD,新的RDD叫MappedRDD

(例1)

1

2

3

4

5

6

7

8

9

10

object Map {

def main(args: Array[String]) {

val conf =newSparkConf().setMaster("local").setAppName("map")

val sc =newSparkContext(conf)

val rdd = sc.parallelize(1to10)//创建RDD

val map = rdd.map(_*2)//对RDD中的每个元素都乘于2

map.foreach(x => print(x+" "))

sc.stop()

}

}

输出:

2 4 6 8 10 12 14 16 18 20

(RDD依赖图:红色块表示一个RDD区,黑色块表示该分区集合,下同)

2.flatMap(func):与map类似,但每个元素输入项都可以被映射到0个或多个的输出项,最终将结果”扁平化“后输出

(例2)

1

2

3

4

//...省略sc

val rdd = sc.parallelize(1to5)

val fm = rdd.flatMap(x => (1to x)).collect()

fm.foreach( x => print(x +" "))

输出:

1 1 2 1 2 3 1 2 3 4 1 2 3 4 5

如果是map函数其输出如下:

Range(1) Range(1, 2) Range(1, 2, 3) Range(1, 2, 3, 4) Range(1, 2, 3, 4, 5)

(RDD依赖图)

3.mapPartitions(func):类似与map,map作用于每个分区的每个元素,但mapPartitions作用于每个分区工

func的类型:Iterator[T] => Iterator[U]

假设有N个元素,有M个分区,那么map的函数的将被调用N次,而mapPartitions被调用M次,当在映射的过程中不断的创建对象时就可以使用mapPartitions比map的效率要高很多,比如当向数据库写入数据时,如果使用map就需要为每个元素创建connection对象,但使用mapPartitions的话就需要为每个分区创建connetcion对象

(例3):输出有女性的名字:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

object MapPartitions {

//定义函数

def partitionsFun(/*index : Int,*/iter : Iterator[(String,String)]) : Iterator[String] = {

var woman = List[String]()

while(iter.hasNext){

val next = iter.next()

next match {

case(_,"female") => woman =/*"["+index+"]"+*/next._1 :: woman

case_ =>

}

}

returnwoman.iterator

}

def main(args: Array[String]) {

val conf =newSparkConf().setMaster("local").setAppName("mappartitions")

val sc =newSparkContext(conf)

val l = List(("kpop","female"),("zorro","male"),("mobin","male"),("lucy","female"))

val rdd = sc.parallelize(l,2)

val mp = rdd.mapPartitions(partitionsFun)

/*val mp = rdd.mapPartitionsWithIndex(partitionsFun)*/

mp.collect.foreach(x => (print(x +" ")))//将分区中的元素转换成Aarray再输出

}

}

输出:

kpop lucy

其实这个效果可以用一条语句完成

1

val mp = rdd.mapPartitions(x => x.filter(_._2 =="female")).map(x => x._1) 

之所以不那么做是为了演示函数的定义

(RDD依赖图)

4.mapPartitionsWithIndex(func):与mapPartitions类似,不同的时函数多了个分区索引的参数

func类型:(Int, Iterator[T]) => Iterator[U]

(例4):将例3橙色的注释部分去掉即是

输出:(带了分区索引)

[0]kpop [1]lucy

5.union(ortherDataset):将两个RDD中的数据集进行合并,最终返回两个RDD的并集,若RDD中存在相同的元素也不会去重

1

2

3

4

5

6

//省略sc

val rdd1 = sc.parallelize(1to3)

val rdd2 = sc.parallelize(3to5)

val unionRDD = rdd1.union(rdd2)

unionRDD.collect.foreach(x => print(x +" "))

sc.stop 

输出:

1 2 3 3 4 5

  

6.intersection(otherDataset):返回两个RDD的交集

1

2

3

4

5

6

//省略sc

val rdd1 = sc.parallelize(1to3)

val rdd2 = sc.parallelize(3to5)

val unionRDD = rdd1.intersection(rdd2)

unionRDD.collect.foreach(x => print(x +" "))

sc.stop 

输出:

3 4

7.distinct([numTasks]):对RDD中的元素进行去重

1

2

3

4

5

//省略sc

val list = List(1,1,2,5,2,9,6,1)

val distinctRDD = sc.parallelize(list)

val unionRDD = distinctRDD.distinct()

unionRDD.collect.foreach(x => print(x +" "))  

输出:

1 6 9 5 2

8.cartesian(otherDataset):对两个RDD中的所有元素进行笛卡尔积操作

1

2

3

4

5

//省略

val rdd1 = sc.parallelize(1to3)

val rdd2 = sc.parallelize(2to5)

val cartesianRDD = rdd1.cartesian(rdd2)

cartesianRDD.foreach(x => println(x +" ")) 

输出:

复制代码

(1,2) (1,3) (1,4) (1,5) (2,2) (2,3) (2,4) (2,5) (3,2) (3,3) (3,4) (3,5)

复制代码

(RDD依赖图)

9.coalesce(numPartitions,shuffle):对RDD的分区进行重新分区,shuffle默认值为false,当shuffle=false时,不能增加分区数

目,但不会报错,只是分区个数还是原来的

(例9:)shuffle=false

1

2

3

4

//省略

val rdd = sc.parallelize(1to16,4)

val coalesceRDD = rdd.coalesce(3)//当suffle的值为false时,不能增加分区数(即分区数不能从5->7)

println("重新分区后的分区个数:"+coalesceRDD.partitions.size) 

输出:

重新分区后的分区个数:3
//分区后的数据集
List(1, 2, 3, 4) List(5, 6, 7, 8) List(9, 10, 11, 12, 13, 14, 15, 16) 

(例9.1:)shuffle=true

1

2

3

4

5

//...省略

val rdd = sc.parallelize(1to16,4)

val coalesceRDD = rdd.coalesce(7,true)

println("重新分区后的分区个数:"+coalesceRDD.partitions.size)

println("RDD依赖关系:"+coalesceRDD.toDebugString)  

输出:

复制代码

重新分区后的分区个数:5 RDD依赖关系:(5) MapPartitionsRDD[4] at coalesce at Coalesce.scala:14 [] | CoalescedRDD[3] at coalesce at Coalesce.scala:14 [] | ShuffledRDD[2] at coalesce at Coalesce.scala:14 [] +-(4) MapPartitionsRDD[1] at coalesce at Coalesce.scala:14 [] | ParallelCollectionRDD[0] at parallelize at Coalesce.scala:13 [] //分区后的数据集
List(10, 13) List(1, 5, 11, 14) List(2, 6, 12, 15) List(3, 7, 16) List(4, 8, 9) 

复制代码

(RDD依赖图:coalesce(3,flase))

(RDD依赖图:coalesce(3,true))

10.repartition(numPartition):是函数coalesce(numPartition,true)的实现,效果和例9.1的coalesce(numPartition,true)的一样

11.glom():将RDD的每个分区中的类型为T的元素转换换数组Array[T]

1

2

3

4

5

//省略

val rdd = sc.parallelize(1to16,4)

val glomRDD = rdd.glom()//RDD[Array[T]]

glomRDD.foreach(rdd => println(rdd.getClass.getSimpleName))

sc.stop 

输出:

int[] //说明RDD中的元素被转换成数组Array[Int]

12.randomSplit(weight:Array[Double],seed):根据weight权重值将一个RDD划分成多个RDD,权重越高划分得到的元素较多的几率就越大

1

2

3

4

5

6

7

//省略sc

val rdd = sc.parallelize(1to10)

val randomSplitRDD = rdd.randomSplit(Array(1.0,2.0,7.0))

randomSplitRDD(0).foreach(x => print(x +" "))

randomSplitRDD(1).foreach(x => print(x +" "))

randomSplitRDD(2).foreach(x => print(x +" "))

sc.stop 

输出:

2 4
3 8 9

1 5 6 7 10

### 回答1: Spark中的RDD(Resilient Distributed Datasets)是一种分布式的数据结构,它可以被分割成多个分区,每个分区可以在不同的节点上进行计算。RDD提供了一系列转换和操作函数,可以对RDD进行各种操作。 RDD转换函数包括map、filter、flatMap、union、distinct、groupByKey、reduceByKey、sortByKey等。这些函数可以对RDD进行转换操作,生成新的RDDRDD操作函数包括count、collect、reduce、take、foreach等。这些函数可以对RDD进行操作,返回结果或者将结果输出到外部系统。 在使用RDD时,需要注意一些问题,如RDD的惰性计算、RDD的持久化、RDD的分区等。同时,还需要根据实际情况选择合适的RDD转换和操作函数,以达到最优的计算效果。 总之,Spark中的RDD转换和操作函数是非常重要的,掌握它们可以帮助我们更好地使用Spark进行分布式计算。 ### 回答2: Spark是一个基于内存计算的分布式计算框架,可以实现大规模数据集的快速处理。在Spark中,RDD(弹性分布式数据集)是数据处理的核心概念,它是一种可以分区、并行计算和容错的不可变数据结构。而Spark中的函数式编程模型则将RDD转换与操作都看做是函数的调用,从而简洁明了,易于理解和操作。 在Spark中,解决一个具体问题通常涉及一系列RDD转换和操作。RDD转换包括对原有RDD进行过滤、映射、聚合等处理,得到新的RDD;操作则是对新的RDD进行输出、保存、统计、排序等操作。以下介绍几种常见的RDD转换和操作函数。 1. map函数 map函数是一种转换函数,它可以将一个RDD中每个元素通过一个用户定义的函数映射到另一个RDD中,并得到新的RDD。例如,将一个整型RDD中的每个元素都乘以2后得到一个新的整型RDD: ``` val rdd1 = sc.parallelize(Array(1, 2, 3, 4)) val rdd2 = rdd1.map(x => x*2) ``` 2. filter函数 filter函数也是一种转换函数,它可以根据用户定义的条件过滤一个RDD中的元素,并得到一个新的RDD。例如,将一个字符串RDD中长度大于5的元素过滤出来得到一个新的字符串RDD: ``` val rdd1 = sc.parallelize(Array("hello", "world", "spark", "rdd")) val rdd2 = rdd1.filter(x => x.length > 5) ``` 3. reduce函数 reduce函数是一种操作函数,它可以将一个RDD中的元素按照用户定义的函数进行聚合并得到一个结果。例如,将一个整型RDD中的所有元素相加得到一个整数结果: ``` val rdd1 = sc.parallelize(Array(1, 2, 3, 4)) val result = rdd1.reduce((x, y) => x + y) ``` 4. collect函数 collect函数也是一种操作函数,它可以将一个RDD中的所有元素收集起来并输出到Driver端。然而,使用collect函数需要注意RDD的大小,如果RDD很大,就可能会出现内存溢出的情况。例如,将一个整型RDD中的所有元素收集起来并输出到屏幕: ``` val rdd1 = sc.parallelize(Array(1, 2, 3, 4)) val result = rdd1.collect() result.foreach(println) ``` 5. saveAsTextFile函数 saveAsTextFile函数也是一种操作函数,它可以将一个RDD中的所有元素保存到指定的文本文件中。例如,将一个字符串RDD中的所有元素保存到hdfs的一个文本文件中: ``` val rdd1 = sc.parallelize(Array("hello", "world", "spark", "rdd")) rdd1.saveAsTextFile("hdfs://localhost:8020/user/abc/output") ``` 总之,Spark中的RDD转换和操作函数具有弹性、高效、简单等特点,能够满足各种大规模数据处理需求。需要特别注意的是,Spark中的函数式编程模型是基于JVM的,因此要充分利用内存和CPU资源,需要对集群配置和调优进行一定的优化和测试。 ### 回答3: Spark中的RDD(Resilient Distributed Datasets)是分布式的弹性数据集,它可以在大规模集群上并行化地计算,并且提供了一系列转换和操作函数。其中,Spark提供的Spark函数简单易用,具有高效的数据处理能力,可以帮助开发者快速开发分布式应用程序。 RDD转换函数是将一个RDD转换成另一个RDD函数转换后的RDD通常包含了数据处理、筛选和过滤后的新数据集,可以用来接着进行后续的计算。 例如,map函数可以将RDD中的每个元素应用一个函数,然后返回一个新的转换过的RDD: ``` val originalData = sc.parallelize(List(1, 2, 3, 4, 5)) val mappedData = originalData.map(x => x * 2) ``` 这里,map函数将原始数据中的每个元素都乘上了2,返回了一个新的RDD。 除了map函数, 还有flatMap、filter、groupBy等常用的转换函数,都可以帮助我们对RDD做出各种各样的数据处理和转换RDD操作函数则是对RDD进行真正的计算操作,例如reduce、count、collect等函数,这些函数会触发Spark的分布式计算引擎执行真正的计算任务。 比如,reduce函数可以将RDD中的所有元素进行聚合,返回一个单一的结果: ``` val originalData = sc.parallelize(List(1, 2, 3, 4, 5)) val reducedData = originalData.reduce(_ + _) ``` 这里,reduce函数将原始数据中的所有元素进行相加操作,返回了一个整数类型的结果。 Spark提供的操作函数非常丰富,从基本的聚合、排序、统计操作,到高级的机器学习和图形处理等操作,开发者可以根据不同的业务需求灵活选择使用。 总之,Spark中的RDD转换和操作函数是分布式数据处理的核心之一,通过这些函数,开发者能够方便地对海量数据进行分布式的计算和处理。同时,Spark也提供了丰富的API和工具,便于开发者进行高效的Spark应用程序开发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值