前言
day12,我们学习了Spark RDD。今天介绍下并演示下Spark 高级算子的Demo。
什么是算子
RDD调用的方法就是算子,说白了,算子就是一个函数,用于RDD数据的转换或计算。
aggregate
aggregate是Spark官方提供的一个高级算子,它能对RDD数据按分区先进行局部聚合,最后进行全局聚合。
scala> var rdd1 = sc.parallelize(List("12","34","567","8901"),2)
rdd1: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[0] at parallelize at <console>:24
scala> def fun1(index:Int,iter:Iterator[String]):Iterator[String]={
| iter.toList.map(x => "[partId: " + index + ",value:" + x + "]").iterator}
fun1: (index: Int, iter: Iterator[String])Iterator[String]
#可以看到,获取到分区号,一共有2个分区
scala> rdd1.mapPartitionsWithIndex(fun1).collect
res0: Array[String] = Array([partId: 0,value:12], [partId: 0,value:34], [partId: 1,value:567], [partId: 1,value:8901])
scala>
#求每个分区元素长度的大最值,然后把各个分区的最大值相加
scala> rdd1.aggregate("")((x,y)=>math.max(x.length,y.length).toString,(x,y)=>x+y)
res1: String = 24
scala>
scala> rdd1.aggregate("")((x,y)=>math.max(x.length,y.length).toString,(x,y)=>x+y)
res2: String = 42
scala> rdd1.aggregate("")((x,y)=>math.max(x.length,y.length).toString,(x,y)=>x+y)
res3: String = 24
上面的运行结果可以看到,结果有时候是24,有时候是42,具体原因分析如下
第一个分区的元素:“12”,“34”
第一次比较:"",“12” ==>长度大的是2,得到的结果是2.toString,也就是"2"
第二次比较:“2”,“34” ==>长度大的是2,得到的结果是2.toString,也就是"2"
第一个分区的元素:“567”,“8901”
第一次比较:"",“567” ==>长度大的是3,得到的结果是3.toString,也就是"3"
第二次比较:“3”,“8901” ==>长度大的是4,得到的结果是4.toString,也就是"4"
最后全局计算的元素:“2”,“4”
如果是第一个分区先计算完成,则全局计算得出的结果是"24"
如果是第二个分区先计算完成,则全局计算得出的结果是"42"
aggregateByKey
aggregateByKey和aggregate的功能差不多,唯一不同的是针对的数据不同。
aggregate是针对集合的。
aggregateByKey是针对key-value类型的。
scala> var rdd1 = sc.parallelize(List(("Tom",20),("Tom",25),("JinRui",2),("JinRui",18),("Liky",30),("Liky",20),("JinRui",10)),2)
rdd1: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[12] at parallelize at <console>:24
scala> def fun2(index:Int,iter:Iterator[(String,Int)]):Iterator[String]={
| iter.toList.map(x => "[PartId: " + index + ",value: " + x + "]").iterator}
fun2: (index: Int, iter: Iterator[(String, Int)])Iterator[String]
scala> rdd1.mapPartitionsWithIndex(fun2).collect
res17: Array[String] = Array([PartId: 0,value: (Tom,20)], [PartId: 0,value: (Tom,25)], [PartId: 0,value: (JinRui,2)], [PartId: 1,value: (JinRui,18)], [PartId: 1,value: (Liky,30)], [PartId: 1,value: (Liky,20)], [PartId: 1,value: (JinRui,10)])
#对每个分区求最大值,最后把最大值加起来。
scala> var rdd2 = rdd1.aggregateByKey(0)(math.max(_,_),_+_)
rdd2: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[14] at aggregateByKey at <console>:26
scala> rdd2.collect
res19: Array[(String, Int)] = Array((Tom,25), (JinRui,20), (Liky,30))
scala>
repartition和coalesce
repartition和coalesce的功能都是重分区。
coalesce:进行重分区的时候默认不会进行shuffle。
repartition:进行重分区的时候默认会进行shuffle。
scala> var rdd1 = sc.parallelize(List(1,2,3,4,5,6,7),2)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:24
#指定重分区为 3 个分区
scala> var rdd2 = rdd1.repartition(3)
rdd2: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[8] at repartition at <console>:26
#查看重分区前面的分区数
scala> rdd1.partitions.length
res2: Int = 2
scala> rdd2.partitions.length
res1: Int = 3
#使用coalesce进行分区,虽然指定了重分区为3个分区,但是查看分区后的分区数,还是2,因为coalesce默认是不进行shuffle
scala> var rdd3 = rdd1.coalesce(3)
rdd3: org.apache.spark.rdd.RDD[Int] = CoalescedRDD[9] at coalesce at <console>:26
scala> rdd3.partitions.length
res3: Int = 2
#使用coalesce进行重分区时,只有指定为true,才会进行shuffle
scala> var rdd4 = rdd1.coalesce(3,true)
rdd4: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[13] at coalesce at <console>:26
scala> rdd4.partitions.length
res4: Int = 3
scala>
其它
Spark中的算子非常多,这里不一一列举了,有兴趣的朋友可以到Saprk官方查阅。