Spark RDD Operations

Spark RDD Operations

 

RDD支持两种操作:转换(transformation)从现有的数据集创建一个新的数据集;而动作(actions)在数据集上运行计算后,返回一个值给驱动程序。 例如,map就是一种转换,它将数据集每一个元素都传递给函数,并返回一个新的分布数据集表示结果。另一方面,reduce是一种动作,通过一些函数将所有的元素叠加起来,并将最终结果返回给Driver程序。(不过还有一个并行的reduceByKey,能返回一个分布式数据集)

 

Spark中的所有转换都是惰性的,也就是说,他们并不会直接计算结果。相反的,它们只是记住应用到基础数据集(例如一个文件)上的这些转换动作。只有当发生一个要求返回结果给Driver的动作时,这些转换才会真正运行。这个设计让Spark更加有效率的运行。例如,我们可以实现:通过map创建的一个新数据集,并在reduce中使用,最终只返回reduce的结果给driver,而不是整个大的新数据集。

 

默认情况下,每一个转换过的RDD都会在你在它之上执行一个动作时被重新计算。不过,你也可以使用persist(或者cache)方法,持久化一个RDD在内存中。在这种情况下,Spark将会在集群中,保存相关元素,下次你查询这个RDD时,它将能更快速访问。在磁盘上持久化数据集,或在集群间复制数据集也是支持的,这些选项将在本文档的下一节进行描述。

 

下面的表格列出了目前所支持的转换和动作(详情请参见 RDD API doc):

 

转换(transformation)

map(func)

返回一个新分布式数据集,由每一个输入元素经过func函数转换后组成

filter(func)

返回一个新数据集,由经过func函数计算后返回值为true的输入元素组成

flatMap(func)

类似于map,但是每一个输入元素可以被映射为0或多个输出元素(因此func应该返回一个序列,而不是单一元素)

mapPartitions(func)

类似于map,但独立地在RDD的每一个分块上运行,因此在类型为TRDD上运行时,func的函数类型必须是Iterator[T] => Iterator[U]

mapPartitionsWithSplit(func)

类似于mapPartitions, func带有一个整数参数表示分块的索引值。因此在类型为TRDD上运行时,func的函数类型必须是(Int, Iterator[T]) => Iterator[U]

sample(withReplacement,fraction, seed)

根据fraction指定的比例,对数据进行采样,可以选择是否用随机数进行替换,seed用于指定随机数生成器种子

union(otherDataset)

返回一个新的数据集,新数据集是由源数据集和参数数据集联合而成

distinct([numTasks]))

返回一个包含源数据集中所有不重复元素的新数据集

groupByKey([numTasks])

在一个(K,V)对的数据集上调用,返回一个(KSeq[V])对的数据集

注意:默认情况下,只有8个并行任务来做操作,但是你可以传入一个可选的numTasks参数来改变它

reduceByKey(func, [numTasks])

在一个(KV)对的数据集上调用时,返回一个(KV)对的数据集,使用指定的reduce函数,将相同key的值聚合到一起。类似groupByKeyreduce任务个数是可以通过第二个可选参数来配置的

sortByKey([ascending], [numTasks])

在一个(KV)对的数据集上调用,K必须实现Ordered接口,返回一个按照Key进行排序的(KV)对数据集。升序或降序由ascending布尔参数决定

join(otherDataset, [numTasks])

在类型为(K,V)和(K,W)类型的数据集上调用时,返回一个相同key对应的所有元素对在一起的(K, (V, W))数据集

cogroup(otherDataset, [numTasks])

在类型为(K,V)和(K,W)的数据集上调用,返回一个 (K, Seq[V], Seq[W])元组的数据集。这个操作也可以称之为groupwith

cartesian(otherDataset)

笛卡尔积,在类型为 T U 类型的数据集上调用时,返回一个 (T, U)对数据集(两两的元素对)

 

 

动作(actions)

reduce(func)

通过函数func(接受两个参数,返回一个参数)聚集数据集中的所有元素。这个功能必须可交换且可关联的,从而可以正确的被并行执行。

collect()

在驱动程序中,以数组的形式,返回数据集的所有元素。这通常会在使用filter或者其它操作并返回一个足够小的数据子集后再使用会比较有用。

count()

返回数据集的元素的个数。

first()

返回数据集的第一个元素(类似于take(1))

take(n)

返回一个由数据集的前n个元素组成的数组。注意,这个操作目前并非并行执行,而是由驱动程序计算所有的元素

takeSample(withReplacement,num, seed)

返回一个数组,在数据集中随机采样num个元素组成,可以选择是否用随机数替换不足的部分,Seed用于指定的随机数生成器种子

saveAsTextFile(path)

将数据集的元素,以textfile的形式,保存到本地文件系统,HDFS或者任何其它hadoop支持的文件系统。对于每个元素,Spark将会调用toString方法,将它转换为文件中的文本行

saveAsSequenceFile(path)

将数据集的元素,以Hadoop sequencefile的格式,保存到指定的目录下,本地系统,HDFS或者任何其它hadoop支持的文件系统。这个只限于由key-value对组成,并实现了Hadoop的Writable接口,或者隐式的可以转换为Writable的RDD。(Spark包括了基本类型的转换,例如Int,Double,String,等等)

countByKey()

对(K,V)类型的RDD有效,返回一个(K,Int)对的Map,表示每一个key对应的元素个数

foreach(func)

在数据集的每一个元素上,运行函数func进行更新。这通常用于边缘效果,例如更新一个累加器,或者和外部存储系统进行交互,例如HBase

 

 

 

# 创建一个变量data,类型为Array[Int]

scala> var data= Array(1, 2, 3, 4)

data: Array[Int] = Array(1, 2, 3, 4)

 

# 将data转化为RDD

scala> vardistData = sc.parallelize(data)

distData: org.apache.spark.rdd.RDD[Int] =ParallelCollectionRDD[23] at parallelize at <console>:14

 

# 应用map把distData的每个元素的值加1

# 其中collect是action方法返回数据集的所有元素

scala>distData.map(x => x + 1).collect()

14/07/10 15:40:28 INFO scheduler.DAGScheduler: Stage 1 (collectat <console>:17) finished in 0.006 s

14/07/10 15:40:28 INFO spark.SparkContext: Job finished: collectat <console>:17, took 0.017348 s

res12: Array[Int] = Array(2, 3, 4, 5)

 

# 应用filter把distData中元素值为1的过滤出来

scala>distData.filter(x => x == 1).collect()

14/07/10 15:45:28 INFO spark.SparkContext: Job finished: collectat <console>:17, took 0.011363 s

res20: Array[Int] = Array(1)

 

# 应用flatMap把distData的所有元素做扁平化扩展

scala> distData.flatMap(x => Array(x, 5, 6, 7)).collect()

14/07/10 15:48:57 INFO spark.SparkContext: Job finished: collectat <console>:17, took 0.013091 s

res22: Array[Int] = Array(1, 5, 6, 7, 2, 5, 6, 7, 3, 5, 6, 7, 4,5, 6, 7)

 

# mapPartitions(func)

  还没搞定。。。

# mapPartitionsWithIndex(func)

  同没搞定。。。

# sample按比例采样,结果比较奇怪

scala>distData.sample(false, 0.5, 0).collect()

res26: Array[Int] = Array(2)

 

scala>distData.sample(false, 1, 0).collect()

res27: Array[Int] = Array(1, 2, 3, 4)

 

 

scala>distData.sample(false, 0.9, 0).collect()

res28: Array[Int] = Array(1, 2, 3)

 

 

scala>distData.sample(false, 0.5, 0).collect()

res29: Array[Int] = Array(2)

 

scala>distData.sample(true, 0.5, 0).collect()

res30: Array[Int] = Array(1, 4)

 

scala>distData.sample(true, 0.5, 1).collect()

res31: Array[Int] = Array(1, 3, 3, 3, 3, 3, 4)

 

scala>distData.sample(false, 2, 0).collect()

res1: Array[Int] = Array(1, 2, 3, 4)

 

# 用union合并两个RDD,结果显示没有去重,仅是简单的合并

scala> valtmpData = sc.parallelize(Array(3, 4, 5, 6))

scala>distData.union(tmpData).collect()

res3: Array[Int] = Array(1, 2, 3, 4, 3, 4, 5, 6)

 

#  intersection,竟然没有这个方法,我用的0.8的spark

# 好吧,回头搞个1.0的spark再试

scala>distData.intersection(tmpData).collect()

<console>:19: error: value intersection is not a member oforg.apache.spark.rdd.RDD[Int]

      distData.intersection(tmpData).collect()

# 应该返回res3: Array[Int] = Array(3, 4)才对嘛!

# 用distinct返回去重后的元素

scala>distData.map(x => x % 2).distinct().collect()

res9: Array[Int] = Array(0, 1)

 

# groupByKey

scala>distData.map(x => (x%2, x)).collect()

res18: Array[(Int, Int)] = Array((1,1), (0,2), (1,3), (0,4))

scala>distData.map(x => (x%2, x)).groupByKey().collect()

res15: Array[(Int, Seq[Int])] = Array((0,ArrayBuffer(2, 4)),(1,ArrayBuffer(1, 3)))

 

#  reduceByKey

scala>distData.map(x => (x%2, x)).reduceByKey(_ + _).collect()

res17: Array[(Int, Int)] = Array((0,6), (1,4))

 

#  sortByKey 按key降序排序,value顺序不变

scala> distData.map(x => (x%2, x)).sortByKey(false).collect()

res21: Array[(Int, Int)] = Array((1,1), (1,3), (0,2), (0,4))

 

# join,只join了key相同的部分,对应自然连接

scala>distData.map(x => (x, x)).join(tmpData.map(x => (x, x))).collect()

res22: Array[(Int, (Int, Int))] = Array((3,(3,3)), (4,(4,4)))

 

# cogroup 相当于全连接,从结果可以看到和join的区别

scala>distData.map(x => (x, x)).cogroup(tmpData.map(x => (x, x))).collect()

res23: Array[(Int, (Seq[Int], Seq[Int]))] =Array((1,(ArrayBuffer(1),ArrayBuffer())), (2,(ArrayBuffer(2),ArrayBuffer())),(3,(ArrayBuffer(3),ArrayBuffer(3))), (4,(ArrayBuffer(4),ArrayBuffer(4))),(5,(ArrayBuffer(),ArrayBuffer(5))), (6,(ArrayBuffer(),ArrayBuffer(6))))

 

# cartesian 返回两个集合的笛卡尔集

scala>distData.cartesian(tmpData).collect()

res24: Array[(Int, Int)] = Array((1,3), (1,4), (1,5), (1,6),(2,3), (2,4), (2,5), (2,6), (3,3), (3,4), (3,5), (3,6), (4,3), (4,4), (4,5),(4,6))

 

# reduce 返回所有元素的和

scala>distData.reduce(_ + _)

res32: Int = 10

 

# count

scala>distData.count()

res33: Long = 4

 

# first

scala>distData.first()

res34: Int = 1

 

# take,num大于数据个数时返回全部数据

scala>distData.take(2)

res35: Array[Int] = Array(1, 2)

 

scala>distData.take(5)

res36: Array[Int] = Array(1, 2, 3, 4)

 

# countByKey

scala>distData.map(x => (x%2, x)).countByKey()

res40: scala.collection.Map[Int,Long] = Map(1 -> 2, 0 ->2)

 

# takeSample

scala> distData.takeSample(false, 2, 0)

res38: Array[Int] = Array(4, 3)

 

# foreach

scala> val accum= sc.accumulator(0)

accum: org.apache.spark.Accumulator[Int] = 0

 

scala>distData.foreach(x => accum += x)

14/07/10 13:40:18 INFO scheduler.DAGScheduler: Stage 24 (foreachat <console>:19) finished in 0.012 s

14/07/10 13:40:18 INFO spark.SparkContext: Job finished: foreachat <console>:19, took 0.033934 s

 

scala>accum.value

res36: Int = 10

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值