1) groupByKey案例
1.作用:groupByKey 对每一个进行操作,但只生成一个sequence
2.需求: 创建一个pairRDD,将相同key对应值聚合到一个sequence中,并计算相同对应值的相加结果
//创建一个RDD算子,指定分区数2
val ListRDD: RDD[String] = sc.makeRDD(List("Abo", "Spark", "Hadoop",
"Python", "Python", "Scala", "Spark", "Spark"), 2)
//转换结构将ListRDD集合中每一个元素映射成二元组("Abo",1)形式
val MapRDD: RDD[(String, Int)] = ListRDD.map((_, 1))
//将上述MapRDD集合中的元素排序(二元组第一个元素为Key)
val GroupByKeyRDD: RDD[(String, Iterable[Int])] = MapRDD.groupByKey()
返回结果:
(Python,CompactBuffer(1, 1))
(Scala,CompactBuffer(1))
(Abo,CompactBuffer(1))
(Spark,CompactBuffer(1, 1, 1))
(Hadoop,CompactBuffer(1))
上一步的基础上对相同key的value值进行求和
val groupBySum: RDD[(String, Int)] = GroupByKeyRDD.map(x => (x._1, x._2.sum))
groupBySum.collect().foreach(println)
(Python,2)
(Scala,1)
(Abo,1)
(Spark,3)
(Hadoop,1)
2) reduceByKey(func,[numTasks]) 案例
1.在一个(K,V) 的RDD上调用,返回一个(K,V)的RDD,使用指定的reduce函数,将相同的key值聚合到一起,reduce任务可以通过可选参数numTasks来进行设置
2.需求,创建一个pairRDD,计算相同key对应值的相加结果
val ListRDD: RDD[(String, Int)] = sc.makeRDD(List(("Abo", 1), ("Spark", 1), ("Hadoop", 1),
("Python", 1), ("Python", 1), ("Scala", 1), ("Spark", 1), ("Spark", 1)), 2)
//计算相同key对应值的相加结果
val reduceByKeyRDD: RDD[(String, Int)] = ListRDD.reduceByKey(_ + _)
返回结果:
(Python,4)
(Scala,2)
(Abo,3)
(Spark,4)
(Hadoop,1)
reduceByKey和groupByKey的区别
1.reduceByKey: 按照key进行聚合,在shuffle之间有combine(预聚合)操作,返回结果是RDD[k,v]
2.groupByKey:按照key进行分组,直接进行shuffle.
3.开发中自然是建议reduceByKey
3) aggregateByKey案例
参数:(zeroValue: U, partitioner: Partitioner)(seqOp: (U, V) => U,
combOp: (U, U) => U)
1.作用: 在kv对的RDD中,按Key将value进行分组合并,合并时,将每个value和初始值seq函数的参数,进行计算,返回的结果作为一个新的kv对,然后再将结果按照key进行合并,最后将每个分组的value传递给combin函数进行计算(先将前两个value进行计算,将返回结果和下一个value传给combin函数,依次类推),将key于计算结果作为一个新的kv对输出
2.参数描述:
(1) zeroValue: 给每一个分区中的每一个key一个初始值
(2) seqOp: 函数用于在每一个分区中用初始值逐步迭代value
(3) combOp: 函数用于合并每个分区中的结果
3.需求: 创建一个pariRDD,取出每个分区相同key对应值的最大值,然后相加.
val ListRDD: RDD[(String, Int)] = sc.makeRDD(Array(("a", 3), ("c", 3), ("c", 6), ("a", 4), ("a", 7), ("b", 10)), 2)
ListRDD.glom.collect().foreach(data => println(data.mkString(",")))
println("-----------------------")
//分区内相同key求最大值,分区间求和
// def aggregateByKey[U: ClassTag](zeroValue: U, partitioner: Partitioner)(seqOp: (U, V) => U,
// combOp: (U, U) => U): RDD[(K, U)] = self.withScope {
//zeroValue:初始值, (seqOp: (U, V) => U:分区内 combOp: (U, U) => U)分区间
val aggRDD: RDD[(String, Int)] = ListRDD.aggregateByKey(0)(math.max(_, _), _ + _)
val aggRDD: RDD[(String, Int)] = ListRDD.aggregateByKey(0)(math.max(_, _), _ + _)
aggRDD.glom().collect().foreach(println)
(a,3),(c,3),(c,6)
(a,4),(a,7),(b,10)
(b,10)
(a,10),(c,6)
4) foldByKey案例
(zeroValue: V)(func: (V, V) => V)
aggregateByKey算子(seqOp: (U, V) => U,
combOp: (U, U) => U)这两个参数在foldByKey视为一个参数,即只能完成一个操作,分区中与合并每个分区所作的操作相同.
val foldRDD: RDD[(String, Int)] = ListRDD.foldByKey(0)(_ + _)
foldRDD.glom().collect().foreach(data=>println(data.mkString(",")))
返回结果:
(a,3),(c,3),(c,6)
(a,4),(a,7),(b,10)
(b,10)
(a,14),(c,9)
需求: 创建一个pairRDD,根据key计算每种key的均值.(先计算每个key出现的次数以及可以对应值的总和,在相除得到结果)
val ListRDD: RDD[(String, Int)] = sc.makeRDD(Array(("c", 10), ("c", 20), ("a",4), ("c", 10),("a", 7),("b",20),("a",28)), 2)
ListRDD.glom.collect().foreach(data => println(data.mkString(",")))
println("*" * 30)
//求ListRDD中的每一个key出现的次数,以及key对应value值的总和
val combineRDD: RDD[(String, (Int, Int))] = ListRDD.combineByKey((_, 1),
(sum1: (Int, Int), v) => (sum1._1 + v, sum1._2 + 1),
(sum2: (Int, Int), sum3: (Int, Int)) => (sum2._1 + sum3._1, sum2._2 + sum3._2))
val resultRDD: RDD[(String, Double)] = combineRDD.map(data => (data._1, data._2._1 / data._2._2.toDouble))
resultRDD.glom().collect().foreach(data=>println(data.mkString(",")))
createCombiner: V => C (_, 1): 将key对应的值映射成一个二元组(“c”,10)=>(10,1)
mergeValue: (C, V) => C (sum1: (Int, Int), v) => (sum1._1 + v, sum1._2 + 1) 元组的第一位与v相加,元组第二位自增1 (10,1) 20==》(30,2)
mergeCombiners: (C, C) => C (sum2: (Int, Int), sum3: (Int, Int)) 元组的第一位与第二位分别累加 (30,2) (10,1) ==>(40,3)
运行结果:
(c,10),(c,20),(a,4)
(c,10),(a,7),(b,20),(a,28)
(b,20.0)
(a,13.0),(c,13.333333333333334)