Spark RDD API 参考示例(一)

来源:互联网 发布:江湖笑歌词.知乎 编辑:程序博客网 时间:2024/06/17 20:05

本文参考Zhen He

1、aggregate

原型
def aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U

含义
aggregate是一个聚合函数,一个RDD分区后,产生多个Partition,在aggregate中需要指定两个处理函数,第一个函数用于对每个分区内部处理,第二个函数用于分区之间的处理。aggregate 的初始值作用于前后两个部分, 分区是严格按照顺序的,顺序不同aggregate 结果就不同。

示例

//分区顺序严重aggregate的结果,分区特点,先平均分配,多的依次放到序号大的分区val z = sc.parallelize(List(1,2,3,4,5,6), 2)//使用parallelize产生2个分区,可以使用mapPartitionWithIndex查看分区//分区结果是(1,2,3)和(4,5,6)z.aggregate(0)(math.max,_+_)res0: Int = 9  特别注意:初始值 0 是加在分区的左边//第一个参数0 表示将0放入到每个分区中,然后每个分区进行计算。每个分区之间汇总时,再次将0放入其中计算//math.max表示对每个分区内部取最大值,第一个分区有(1,2,3),再加上0,所以是(0,1,2,3)取最大值//_+_表示每个分区之间进行相加val x = sc.parallelize(List(1,2,3,4,5,6,7,8,9), 3)x.aggregate(5)(math.max,_+_)res1: Int = 25//分析三个分区为(1,2,3),(4,5,6),(7,8,9)其中aggregate的初始值为5//每次分区计算数据为(5,1,2,3),(5,4,5,6),(5,7,8,9),分别取最大值,得到(5,6,9)//分区之间使用 _+_ 计算时,再次将5,放入其中,所以变成(5,5,6,9)//最后将其相加变成5+5+6+9=25//字符串类型处理val z = sc.parallelize(List("a","b","c","d","e","f"),2)z.aggregate("x")(_ + _, _+_)res2: String = xxdefxabc//第一个分区集合中有("x","a","b","c") 分区内部的聚合结果为"xabc"//由于是并行的聚合,所以"xabc"和"xdef"谁在前面和后面并不知道//分区之间进行聚合时,集合变成了("x","xabc","xdef")//两个高级的示例val z = sc.parallelize(List("12","23","345","4567"),2)z.aggregate("")((x,y) => math.max(x.length, y.length).toString, _+_)res3: String = 42//分为两个区("12","23")和("345","4567")//由于需要使用两个函数,所以这里定义了一个闭包函数,集合中的每两个元素,取出最大的长度。//每个分区进行比较时集合为("","12","34")、("","345","4567")//每个分区聚合之后的结果为("2","4")//分区之间进行聚合时,集合为("","2","4"),再次聚合结构可能是"24"也可能是"42"val z = sc.parallelize(List("12","23","345","4567"),2)z.aggregate("asd")((x,y) => math.min(x.length, y.length).toString, _+_)res4: String = asd11//分区后的结果为("12","23")  ("345","456")//分区内部应用初始值之后的结果为("asd","12","34")   ("asd","345","456")//每个分区中有三个元素,每个分区内部需要多次聚合,分为("asd","12")和("34")//("asd","12")聚合结果是"2", 再与("34")聚合结果是"1"//所以("asd","12","34") 聚合结果是"1"//同理("asd","345","456") 聚合结果是"1"//两个分区之间再次聚合,将初始值应用到其中,得到"asd11"val z = sc.parallelize(List("12","23","345",""),2)z.aggregate("")((x,y) => math.min(x.length, y.length).toString,_+_)res5: String = 10//分区后的结果为("12","23") ("345","")//分区内部应用初始值之后的结果为("","12","23") ("","345","")//有三个元素,需要多次聚合("","12")  ("23")//("","12")聚合结果是"0"  再与("23")聚合,得到的结果是"1"//("","345")聚合结果是"0"  再与("")聚合,得到的结果是"0"//最后两次结果相加,得到的是"10"特别注意:为了说明分区顺序的重要性,请看下面的例子val z = sc.parallelize(List("12","23","","345"),2)z.aggregate("")((x,y) => math.min(x.length, y.length).toString,_+_)res6: String = 11//分区后的结果为("12","23") ("","345")//分区内部应用初始值之后的结果为("","12","23") ("","","345")//有三个元素,需要多次聚合("","12")  ("23")//("","12")聚合结果是"0"  再与("23")聚合,得到的结果是"1"//("","")聚合结果是"0"  再与("345")聚合,得到的结果是"1"//最后两次结果相加,得到的是"11"

2、aggregateByKey[Pair]

原型
def aggregateByKey[U](zeroValue: U)(seqOp: (U, V) ⇒ U, combOp: (U, U) ⇒ U)(implicit arg0: ClassTag[U]): RDD[(K, U)]

含义
aggregateByKey 也是一个聚合函数,一个RDD分区后,产生多个Partition,在aggregateByKey中需要指定两个处理函数,第一个函数用于对每个分区内部处理,第二个函数用于分区之间的处理。aggregateByKey 的初始值只作用于每个分区内部,不影响分区之间聚合,分区是严格按照顺序的,顺序不同aggregateByKey 结果就不同。

示例

val z = sc.parallelize(List( ("cat",2), ("cat", 5), ("pig", 4),("cat", 12), ("dog", 12)), 2)z.aggregateByKey(0)(math.max(_, _), _ + _).collectres1: Array((dog,12), (pig,4), (cat,17))  //分区之后的结果是(("cat",2),("cat",5))   (("pig",4),("cat",12),("dog",12))//应用aggregate的初始值后,第二个分区为: //([("pig",0),("pig","4")],[("cat",0),("cat",12)],[("dog",0),("dog",12)])//使用math.max函数后,结果为(("pig","4"),("cat",12),("dog",12))//如果使用math.min函数后,结果就为(("pig",0),("cat",0),("dog",0))//使用函数_+_聚合时,不会应用初始值z.aggregateByKey(100)(math.max(_, _), _ + _).collectres2: Array((dog,100), (pig,100), (cat,200))

3、cartesian

原型
def cartesian[U: ClassTag](other: RDD[U]): RDD[(T, U)]

含义
cartesian 笛卡尔积,两个RDD中的元素两两组合

示例

val x = sc.parallelize(List(1,2,3,4,5))val y = sc.parallelize(List(6,7,8,9,10))x.cartesian(y).collect//结果是两者由小到大的顺序排列res0: Array[(Int, Int)] = Array((1,6), (1,7), (1,8), (1,9), (1,10), (2,6), (2,7), (2,8), (2,9), (2,10), (3,6), (3,7), (3,8), (3,9), (3,10), (4,6), (5,6), (4,7), (5,7), (4,8), (5,8), (4,9), (4,10), (5,9), (5,10))

4、checkpoint

原型
def checkpoint()

含义
checkpoint 检查点机制,假设你在迭代1000次的计算中在第999次失败了,然后你没有checkpoint,你只能重新开始恢复了,如果恰好你在第998次迭代的时候你做了一个checkpoint,那么你只需要恢复第998次产生的rdd,然后再执行2次迭代完成总共1000的迭代,这样效率就很高,比较适用于迭代计算非常复杂的情况,也就是恢复计算代价非常高的情况,适当进行checkpoint会有很大的好处。

示例

sc.setCheckpointDir("hdfs://192.168.10.71:9000/wc")//检查点目录必须存在val a = sc.parallelize(1 to 5)a.checkpoint//将其结果检查点更新a.collectres1: Long = 5

5、coalesce, repartition

原型
def coalesce ( numPartitions : Int , shuffle : Boolean = false ): RDD [T]
def repartition ( numPartitions : Int ): RDD [T]

含义
repartition 表示对已经分区的数据重新分区,是coalesce 的一个简单应用

示例

val y = sc.parallelize(1 to 10, 5)y.coalesce(2, false).collectres1: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)//coalesce分区中false表示直接分区,不对其重新打乱顺序val z = y.coalesce(2, true)val x = y.repartition(2)z.collectres2: Array[Int] = Array(3, 5, 9, 1, 7, 2, 8, 4, 6, 10)//coalesce分区中false表示重新打乱顺序,再分区,和repartition相等,默认是不打乱顺序的

6、cogroup [Pair], groupWith [Pair]

原型
def cogroup[W](other: RDD[(K, W)]): RDD[(K, (Iterable[V], Iterable[W]))]
def groupWith[W](other: RDD[(K, W)]): RDD[(K, (Iterable[V], Iterable[W]))]
含义
cogroup 超级分组,可以将3个key-value类型的RDD进行分组

示例

//3个key-value类型的RDD分组聚合val x = sc.parallelize(List((1, "apple"), (2, "banana"), (3, "orange"), (4, "kiwi")), 2)val y = sc.parallelize(List((5, "computer"), (1, "laptop"), (1, "desktop"), (4, "iPad")), 2)val z = sc.parallelize(List((3,"iphone"),(1,"xiaomi"),(4,"huawei")),2)x.cogroup(y,z).collectres1: Array((4,(CompactBuffer(kiwi),CompactBuffer(iPad),CompactBuffer(huawei))), (2,(CompactBuffer(banana),CompactBuffer(),CompactBuffer())), (1,(CompactBuffer(apple),CompactBuffer(laptop, desktop),CompactBuffer(xiaomi))), (3,(CompactBuffer(orange),CompactBuffer(),CompactBuffer(iphone))), (5,(CompactBuffer(),CompactBuffer(computer),CompactBuffer())))//分析:如果x中不存在这个元素,那么就会将其值置为空

7、collect, toArray

原型
def collect[U: ClassTag](f: PartialFunction[T, U]): RDD[U]
def toArray(): Array[T]
含义
collect 将RDD数据转换成Scala中的数组并返回

示例

val c = sc.parallelize(List("Gnu", "Cat", "Rat", "Dog", "Gnu", "Rat"), 2)c.collectres1: Array[String] = Array(Gnu, Cat, Rat, Dog, Gnu, Rat)

8、collectAsMap

原型
def collectAsMap(): Map[K, V]

含义
collectAsMap 和collect非常类似,但是,是将数据转换成key-value类型的Map

示例

val a = sc.parallelize(List(1, 2, 1, 3), 1)val b = a.zip(a)//以List中的数字作为key,出现次数作为valueb.collectAsMapres1: scala.collection.Map[Int,Int] = Map(2 -> 2, 1 -> 1, 3 -> 3)

9、combineByKey[Pair]

原型
def combineByKey[C](createCombiner: V => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C): RDD[(K, C)]

含义
combineByKey 高效的实现按照key来聚合,通过在每一个分区内部先聚合,再在分区之间聚合。每个分区内部是通过迭代方式来聚合,效率非常高。

示例

val a = sc.parallelize(List("dog","cat","gnu","salmon","rabbit","turkey","wolf","bear","bee"), 3)val b = sc.parallelize(List(1,1,2,2,2,1,2,2,2), 3)val c = b.zip(a)//将数据分成三个区,使用数字当作key,字符串作为valueval d = c.combineByKey(List(_), (x:List[String], y:String) => y :: x, (x:List[String], y:List[String]) => x ::: y)//combineByKey的三个参数的意思是://第一个分区为((1,"dog"), (1,"cat"), (2,"gnu"))//List(_) 每个分区中的key,每次取该分区中的一个key//第一次取1,初始时x中的List为空,找到第一个key为1的dog,将dog放入到x中的List,然后再找到cat//第二次取2,初始时x中的List为空,找到第一个key为2的gnu//第一个分区得到了((1,("cat","dog")),(2,("gnu")))//同理,第二个分区得到了((2,("salmon","rabbit")),(1,("turkey")))//同理,第三个分区得到了(2,("wolf","bear","bee"))//最后,每个分区之间进行合并,将相同的key的数据合并d.collectres1: Array[(Int, List[String])] = Array((1,List(cat, dog, turkey)), (2,List(gnu, rabbit, salmon, bee, bear, wolf)))

10、context, sparkContext

原型
def compute(split: Partition, context: TaskContext): Iterator[T]

含义
context 返回创建RDD时的SparkContext

示例

val c = sc.parallelize(List("Gnu", "Cat", "Rat", "Dog"), 2)c.contextres1: org.apache.spark.SparkContext = org.apache.spark.SparkContext@74c08828

11、count

原型
def count(): Long

含义
count 返回RDD中存储的元素的个数

示例

val c = sc.parallelize(List("Gnu", "Cat", "Rat", "Dog"), 2)c.countres2: Long = 4

12、countApproxDistinct

原型
def countApproxDistinct(relativeSD: Double = 0.05): Long

含义
countApproxDistinct 近似统计RDD中不重复的值的个数,可以通过relativeSD 来确定统计精度,这种方式适合大规模,分布式的数据快速统计

示例

val z = sc.parallelize(List(1,3,4,1,2,3))z.countApproxDistinct(0.01)res1: Long = 4//countApproxDistinct统计的是去掉重复的数值val a = sc.parallelize(1 to 10000, 20)val b = a++a++a++a++ab.countApproxDistinct(0.1)res2: Long = 8224b.countApproxDistinct(0.05)res3: Long = 9750b.countApproxDistinct(0.01)res4: Long = 9947b.countApproxDistinct(0.001)res5: Long = 10000

13、countApproxDistinctByKey [Pair]

原型
def countApproxDistinctByKey(relativeSD: Double = 0.05): RDD[(K, Long)]

含义
countApproxDistinctByKeycountApproxDistinct 类似,但是他是统计元组中的相同的key的个数,相比于其他统计方式,这种统计速度更快

示例

val a = sc.parallelize(List("Gnu", "Cat", "Rat", "Dog"), 2)val b = sc.parallelize(a.takeSample(true, 100, 0), 5)//产生100个随机的,从a中选取的字符,并分为5个区val c = sc.parallelize(1 to b.count().toInt, 5)//产生1-100的数组,并分为5个区val d = b.zip(c)//将其转换为map类型//按照key来进行统计d.countApproxDistinctByKey(0.1).collectres1: Array((Rat,27), (Cat,25), (Dog,29), (Gnu,24))d.countApproxDistinctByKey(0.01).collectres2:  Array((Rat,27), (Cat,24), (Dog,27), (Gnu,22))

14、countByKey [Pair]

原型
def countByKey(): Map[K, Long]

含义
countByKeycount 类似,但是他是用于统计元组中每个相同的key出现的次数,最后返回的是一个元组

示例

val c = sc.parallelize(List((3, "Gnu"), (3, "Yak"), (5, "Mouse"), (3, "Dog")), 2)c.countByKeyres1: scala.collection.Map[Int,Long] = Map(3 -> 3, 5 -> 1)

15、countByValue [Pair]

原型
def countByValue(): Map[T, Long]

含义
countByValue 计算RDD中不同值出现的次数,以value作为统计的标准。分区统计时,这个操作会将信息合并到单个reduce中去。

示例

val b = sc.parallelize(List(1,2,3,4,5,6,7,8,2,4,2,1,1,1,1,1))b.countByValueres1: Map(5 -> 1, 8 -> 1, 3 -> 1, 6 -> 1, 1 -> 6, 2 -> 3, 4 -> 2, 7 -> 1)
原创粉丝点击