java面试题网站:www.javaoffers.com
aggregate是一个 柯里化函数,首先我们知道一个rdd有可能为多个partition。
a: 相对于fun1 作用于每个partition中的元素的第一个元素,即为每个partition增加一个首元素a, 相对于fun2 作用于 和 a
fun1 : 作用于Rdd中的每个partition,并且遍历执行每个partition中的元素(此时的元素已经增加了a),类似于java中的List集合进行for循环遍历每个元素,并在for循环中执行fun1 函数,
fun2: 作用于 a 和 每个partition经过fun1后对应的结果(组成新的并列,a永远在第一个元素)并 遍历计算,
demo1:
val a = sc.parallelize(List("a","b","c","d"),2) // sc 为sparkContext对象
a.aggregate("8")(_+_,_+_)
输出结果为:"88ab8cd"
demo2:
val a = sc.parallelize(List(2,4,6,2,14,6),2)
a.aggregate(3)(math.max(_,_),_+_)
计算过程为:在第一个分区中拿到最大6
在第二个分区拿到最大14
最后加上一个3
结果为23
下面我来补充一案例详解他的逻辑:
package relax.sparkApi
import org.apache.spark.{SparkConf, SparkContext}
object sparkApiDemo {
def main(args: Array[String]): Unit = {
val sc = new SparkContext(new SparkConf().setMaster("local").setAppName("aggregate"))
// val rdd1 = sc.parallelize(List(1,2,3,4,5,6),2)
// val i = rdd1.aggregate(0)(math.max(_,_),_+_)
// println(i)
//
var hs = (a: String,b:Any)=>{ //第一个函数 打印用 :
println("---------------------")
println(a+" : "+b)
a+" : "+b
}
var hd = (a:String,b: String)=>{ //第二个函数 打印用 +
println("---------------------")
println(a+" + " +b)
a+" + "+b
}
val rdd2 = sc.parallelize(List('1',"2","3","4","5","6"),2) //分两个区
val str = rdd2.aggregate("i")(hs,hd)//开始执行
println(str) //打印最终的结果
}
}
我们来工作console 打印的信息来了解:
18/11/14 19:56:35 INFO BlockManagerInfo: Added broadcast_0_piece0 in memory on localhost:64776 (size: 1162.0 B, free: 3.8 GB)
18/11/14 19:56:35 INFO SparkContext: Created broadcast 0 from broadcast at DAGScheduler.scala:861
18/11/14 19:56:35 INFO DAGScheduler: Submitting 2 missing tasks from ResultStage 0 (ParallelCollectionRDD[0] at parallelize at sparkApiDemo.scala:27)
18/11/14 19:56:35 INFO TaskSchedulerImpl: Adding task set 0.0 with 2 tasks
18/11/14 19:56:35 INFO TaskSetManager: Starting task 0.0 in stage 0.0 (TID 0, localhost, PROCESS_LOCAL, 2141 bytes)
18/11/14 19:56:35 INFO Executor: Running task 0.0 in stage 0.0 (TID 0)
---------------------
i : 1
---------------------
i : 1 : 2
---------------------
i : 1 : 2 : 3 // 第一个分区 通过打印信息得知:第一次执行hs函数,把 'i' 传递给 hs 函数中的a , 把分区中遍历的第一个元素传递给b
//并且把hs的结果 再次传递给hs函数参数a ,接着遍历分区中的下一个元素传递给b, 直到遍历分区中的所有元素为止 ,
// 分区中的元素个数代表遍历次数,也代表hs函数的迭代次数,把hs最后一次迭代运行结果返回,作为当前分区的计算结果。
18/11/14 19:56:35 INFO Executor: Finished task 0.0 in stage 0.0 (TID 0). 891 bytes result sent to driver
18/11/14 19:56:35 INFO TaskSetManager: Starting task 1.0 in stage 0.0 (TID 1, localhost, PROCESS_LOCAL, 2099 bytes)
18/11/14 19:56:35 INFO Executor: Running task 1.0 in stage 0.0 (TID 1)
---------------------
i : 4
---------------------
i : 4 : 5
---------------------
i : 4 : 5 : 6 //第二个分区逻辑同上一样 18/11/14 19:56:35 INFO Executor: Finished task 1.0 in stage 0.0 (TID 1). 891 bytes result sent to driver
---------------------
i + i : 1 : 2 : 3 //当所有分区中的元素遍历完毕,也是就hs迭代完毕,则开始执行hd函数,hd函数执行的次数与分区的次数有关
// 把 i 传递给 hd函数中的参数a 然后把第一个分区的结果传给b,得到的新结果再次传递给hd参数的a,遍历下一个分区的结果
//传递给 b, 知道每个分区的每个结果遍历完毕,也就是说hd函数迭代计算的次数与遍历分区结果的次数相同,最后将最终的结果返回
18/11/14 19:56:35 INFO TaskSetManager: Finished task 0.0 in stage 0.0 (TID 0) in 115 ms on localhost (1/2)
18/11/14 19:56:35 INFO TaskSetManager: Finished task 1.0 in stage 0.0 (TID 1) in 29 ms on localhost (2/2)
18/11/14 19:56:35 INFO DAGScheduler: ResultStage 0 (aggregate at sparkApiDemo.scala:28) finished in 0.144 s
18/11/14 19:56:35 INFO TaskSchedulerImpl: Removed TaskSet 0.0, whose tasks have all completed, from pool
---------------------
i + i : 1 : 2 : 3 + i : 4 : 5 : 6 //总结就是 hd的执行逻辑是,i 加(这里的“加, + ” 就是执行一个hd函数)上每一个分区的结果,好比: i + 第一个分区结果+ 第二个分区结果
18/11/14 19:56:35 INFO DAGScheduler: Job 0 finished: aggregate at sparkApiDemo.scala:28, took 0.483809 s i + i : 1 : 2 : 3 + i : 4 : 5 : 6 //打印最终的结果 对应代码中的 “println(str) //打印最终的结果”
18/11/14 19:56:35 INFO SparkContext: Invoking stop() from shutdown hook
18/11/14 19:56:36 INFO SparkUI: Stopped Spark web UI at http://192.168.17.1:4040
18/11/14 19:56:36 INFO DAGScheduler: Stopping DAGScheduler
18/11/14 19:56:36 INFO MapOutputTrackerMasterEndpoint: MapOutputTrackerMasterEndpoint stopped!
18/11/14 19:56:36 INFO MemoryStore: MemoryStore cleared
18/11/14 19:56:36 INFO BlockManager: BlockManager stopped