combineByKey和aggregateByKey的应用分析
package com.zyc.spark
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
* Created with IntelliJ IDEA.
* Author: zyc2913@163.com
* Date: 2020/9/27 16:41
* Version: 1.0
* Description: combineByKey和aggregateByKey的应用分析
*/
object StudyTransformation1 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setMaster("local[*]")
.setAppName("demo3")
val sc = new SparkContext(conf)
/**
* 11. reduceByKey
* 11.1.声明def reduceByKey(func: (V, V) => V): RDD[(K, V)]
* 11.2.参数 二元函数 第一次拿到两个V进行聚合,下次每次拿到聚合结果和新的V再聚合
* 11.3.返回值 RDD[(K, V)] 和原RDD类型一致
* 11.4.作用 对pairRDD按照Key聚合Value
* 11.5.应用举例 统计日志中每个ip出现的次数
*/
val rdd:RDD[String] = sc.textFile("C:\\Users\\Administrator\\Desktop\\book\\logs\\access.log-20190923")
val rdd1:RDD[(String,Int)] = rdd.map(x => (x.split("\\s+")(0), 1)) //切分出ip作为key,value是1
val rdd2:RDD[(String,Int)] = rdd1.reduceByKey((v1: Int, v2: Int) => v1 + v2) //把value聚合相加
//rdd2.foreach(println)
//打印结果如下(只复制了部分)
//(123.53.38.11,883)
//(104.42.137.111,1)
//(49.85.2.243,2)
//(75.164.224.238,2)
//(171.67.70.80,1)
//(39.105.49.192,8)
/**
* 12. groupByKey
* 12.1.声明 def groupByKey(): RDD[(K, Iterable[V])] =
* 12.2.参数
* 12.3.返回值 K和原RDD相同,Value是一个原RDD的V泛型的Iterable
* 12.4.作用 将pairRDD中的数据按照Key进行分组
* 12.5.应用举例:统计ip,每个ip是key,ip出现的次数作为一个数组的值
*/
rdd1.groupByKey()
// .foreach(println)
//打印结果如下(只复制了部分)
//(104.42.137.111,CompactBuffer(1))
//(49.85.2.243,CompactBuffer(1, 1))
//(171.67.70.80,CompactBuffer(1))
//(39.105.49.192,CompactBuffer(1, 1, 1, 1, 1, 1, 1, 1))
/**
* 13. combineByKey
* 13.1.声明 def combineByKey[C](
* createCombiner: V => C, //创建合并器
* mergeValue: (C, V) => C, //合并value
* mergeCombiners: (C, C) => C //聚合合并器
* ): RDD[(K, C)]
* 13.2.参数
* 13.3.返回值 RDD[(K, C)] Key和原RDD相同,V变成了C类型
* 13.4.作用 对RDD按照Key进行聚合,但是聚合过程中V的类型可以改变
* 所有的聚合,底层都是使用combineByKey或者aggregateByKey
* 因为分布式数据集RDD的数据,是保存在不同机器的,需要在每个机器先预聚合,最终再进行全局的聚合
* 13.5.应用举例:计算ip的平均访问量(总访问量total,ip的个数count)
*/
val rdd3:RDD[(Int,(String,Int))] = rdd2.map((1,_))
//rdd3的数据样式如下(key,value):
//(1,(123.53.38.11,883))
//(1,(104.42.137.111,1))
//(1,(49.85.2.243,2))
//(1,(75.164.224.238,2))
/*
val rdd4:RDD[(Int,(Int,Int))] = rdd3.combineByKey(
(v: (String, Int)) => (v._2, 1),
//通过第一个参数的得到的结果如下(key,value):
//(883,1)
//(1,1)
//(2,1)
//(2,1)
(c: (Int, Int), v: (String, Int)) => (c._1 + v._2, c._2 + 1),
// 每个分区内的聚合(key合并,值相加),结果如下
// ( (883,1) (123.53.38.11,883) ) => (883,2)
//( (1,1) (104.42.137.111,1) ) => (1,2)
//( (2,1) (49.85.2.243,2) ) => (2,3)
//((2,1) (75.164.224.238,2) ) => (2,3)
(c1: (Int, Int), c2: (Int, Int)) => (c1._1 + c2._1, c1._2 + c2._2)
//将两个上面的结果合并(key合并,值相加)结果是聚合后的(key,(key,value))
)
rdd4.map(x => x._2._1 * 1.0 / x._2._2) //*1.0表示转换成double型
.foreach(println) //打印结果:149.5
*/
*/
/**
* 14. aggregateByKey
* 14.1.声明 def aggregateByKey
* (zeroValue: U)
* (seqOp: (U, V) => U,
* combOp: (U, U) => U
* ): RDD[(K, U)] =
* 14.2.参数 第一个参数列表,类似combineByKey中的第一个函数,但是aggregateByKey的合并器,不需要使用原RDD中的Value,可以直接声明
* 第二个参数列表,类似combineByKey中的第二第三个函数,作用相同
* 14.3.返回值 RDD[(K, U)] 和原RDD相同K,v变成U泛型
* 14.4.作用 分布式的聚合,类似combineByKey
*/
rdd3.aggregateByKey((0,0))(
(c:(Int,Int),v:(String,Int)) => (c._1+v._2,c._2+1),
(c1:(Int,Int),c2:(Int,Int)) => (c1._1+c2._1,c1._2+c2._2)
)
.foreach(println)
/**
* 15. foldByKey 和aggregateByKey的关系,就像reduceByKey和combineByKey的关系
* 当 aggregateByKey聚合的后两步函数,完全相同时,可以简化写成foldByKey
*
* 15.1.声明def foldByKey(zeroValue: V)(func: (V, V) => V): RDD[(K, V)] =
* 15.2.参数 两个参数列表,
* 15.3.返回值
* 15.4.作用
*
*/
/**
* reduceByKey是combineByKey的简化形式
*
* foldByKey是aggregateByKey的简化形式
*/
}
}