spark aggregateByKey与aggregate

一、aggregateByKey

学过hadoop的话其实就很好理解aggregateByKey了。

def aggregateByKey[U: ClassTag](zeroValue: U)(seqOp: (U, V) => U,combOp: (U, U) => U): RDD[(K, U)] = self.withScope

首先,这个函数是处于数据类型为key-value形式的时候才有的。

然后该函数是柯里化函数,有两个括号的参数:

1、第一个括号是:zeroValue,表示初始值,第二个括号的第一个参数(分区内reduce)会用到,而第二个参数(分区间reduce)不会用到初始值

 

2、第二个括号:

(1)第一个参数:相当于hadoop mapreduce中mapper中的combiner。不同分区(相当于mapreduce的不同map)中的每个分区的数据都各自按key分组,然后key相同的数据列表使用该第一个参数进行执行scala的fold操作。

 

(2)第二个参数:相当于hadoop mapreduce中的reducer。不同的分区经过第一个参数的之后,每个分区的数据合并为一个新的列表。。再使用第二个参数做reduceByKey操作。。

 

下面是我自己根据aggregateByKey原理封装的代码与原版aggregateByKey的对比:

def main(args: Array[String]): Unit = {
        val sc = new SparkContext(new SparkConf().setMaster("local[*]").setAppName("WC"))

        val sourceDataRdd = sc.parallelize(List("a" -> 1, "a" -> 2, "b" -> 3, "z" -> 4, "f" -> 6))

        //初始值(aggregateByKey的第一个括号的参数)
        val zeroValue = 10
        //aggregateByKey第二个括号的第一个参数
        val firstFunc = (left: Int, right: Int) => left + right
        //aggregateByKey第二个括号的第二个参数
        val secondFunc = (left: Int, right: Int) => left + right

        //使用aggregateByKey
        val result1 = sourceDataRdd
                .aggregateByKey(zeroValue)(firstFunc, secondFunc)
                .collect()
                .mkString(",")

        //根据原理自己封装的aggregateByKey
        val result2 = sourceDataRdd
                .mapPartitions(
                    _.toList.groupBy(_._1) //根据key分组
                            .mapValues(_.map(_._2)) // values由List[(String,Int)] 转为 List[Int]
                            .mapValues(_.fold(zeroValue)(firstFunc)) //使用初始值进行fold
                            .toIterator
                )
                .reduceByKey(secondFunc)
                .collect()
                .mkString(",")


        println(result1)
        println(result2)


        sc.stop()
    }

执行输出结果如下:(分区数和我不一样的话输出顺序也不一样。)

(f,16),(a,23),(z,14),(b,13)
(f,16),(a,23),(z,14),(b,13)

 

二、aggregate

参数与aggregateByKey一样。。

1、第一个括号是初始值。

2、第二个括号

(1)第一个参数:对分区内的所有数据(一个list)进行fold操作(初始值就是第一个括号的参数),最终一个分区的结果只会有一个值。

(2)第二个参数:N个分区经过第一个参数之后得到N个值(一个新的list),然后根据这N个值再次进行fold操作(初始值再次被用上),初始值在分区内与分区间都会用上,这是与aggregateByKey的一个不同点,aggregateByKey在分区间时不会使用初始值。

执行输出结果如下:

def main(args: Array[String]): Unit = {
        val sc = new SparkContext(new SparkConf().setMaster("local[*]").setAppName("WC"))

        val sourceDataRdd = sc.parallelize(List(1, 2, 3, 5, 67, 123))

        //初始值(aggregateByKey的第一个括号的参数)
        val zeroValue = 10
        //aggregateByKey第二个括号的第一个参数
        val firstFunc = (left: Int, right: Int) => left + right
        //aggregateByKey第二个括号的第二个参数
        val secondFunc = (left: Int, right: Int) => left + right

        //使用aggregateByKey
        val result1 = sourceDataRdd
                .aggregate(zeroValue)(firstFunc, secondFunc)

        //根据原理自己封装的aggregateByKey
        val result2 = sourceDataRdd
                .mapPartitions(iterator => List(iterator.fold(zeroValue)(firstFunc)).toIterator)
                .collect() //转为scala的集合再使用fold而不是使用rdd本身的fold(因为误会)
                .fold(zeroValue)(secondFunc)
        

        println(result1)
        println(result2)


        sc.stop()
    }

输出结果:、

271
271

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章