本文可以参考:
https://www.jianshu.com/p/09912beb1350
https://blog.csdn.net/faan0966/article/details/80513260
https://blog.csdn.net/u013514928/article/details/56680825
深入理解一下aggregateByKey函数
在计算中,经常会使用到根据key值分组聚合的操作。
相对于reduceybykey,groupbykey没有预先聚合,直接将同key的value进行分组再聚合 shuff耗费严重;而reducebykey是现在各个excutor上分组先聚合 再聚合 效果远高于groupbykey。
多种改进方法:
//使用reduceByKey 来代替groupBykey
val imei_apk_rdd:RDD[(String,Array[(String,Long)])]= imei_resource_df.map(v=>{
val imei = v.getAs[String]("umid")
val apk_name = v.getAs[String]("apk_name")
val cnt = v.getAs[Long]("cnt")
(imei,(apk_name,cnt))
}).rdd.map(v=>(v._1,Array(v._2))).reduceByKey(_++_)
//使用aggregateByKey代替groupBykey
val zero = Set[(String,Long)]()
val imei_apk_rdd:RDD[(String,Array[(String,Long)])]= imei_resource_df.map(v=>{
val imei = v.getAs[String]("umid")
val apk_name = v.getAs[String]("apk_name")
val cnt = v.getAs[Long]("cnt")
(imei,(apk_name,cnt))
}).rdd.aggregateByKey(zero)(
(set, v) => set += v,
(set1, set2) => set1 ++= set2).map(v=>(v._1,v._2.toArray))
//使用combineByKey 来代替groupBykey
val imei_apk_rdd:RDD[(String,Array[(String,Long)])]= imei_resource_df.map(v=>{
val imei = v.getAs[String]("umid")
val apk_name = v.getAs[String]("apk_name")
val cnt = v.getAs[Long]("cnt")
(imei,(apk_name,cnt))
}).rdd.combineByKey(
(v : (String,Long)) => List(v),
(c : List[(String,Long)], v : (String,Long)) => v :: c,
(c1 : List[(String,Long)], c2 : List[(String,Long)]) => c1 ::: c2
).map(v=>(v._1,v._2.toArray))
=========================================================================================
aggregateByKey算子其实相当于是针对不同“key”数据做一个map+reduce规约的操作。
举一个简单的在生产环境中的一段代码
有一些整理好的日志字段,经过处理得到了RDD类型为(String,(String,String))的List格式结果,其中各个String代表的是:(用户名,(访问时间,访问页面url))
同一个用户可能在不同的时间访问了不同或相同的页面,为了合并同一个用户的访问行为,写了下面这段代码,用到aggregateByKey。
val data = sc.parallelize(
List(
("13909029812",("20170507","http://www.baidu.com")),("18089376778",("20170401","http://www.google.com")),("18089376778",("20170508","http://www.taobao.com")),("13909029812",("20170507","http://www.51cto.com"))
)
)
data.aggregateByKey(scala.collection.mutable.Set[(String, String)](), 200)((set, item) => {
set += item
}, (set1, set2) => set1 union set2).mapValues(x => x.toIterable).collect
结果:
res12: Array[(String, Iterable[(String, String)])] = Array((18089376778,Set((20170401,http://www.google.com), (20170508,http://www.taobao.com))), (13909029812,Set((20170507,http://www.51cto.com), (20170507,http://www.baidu.com))))
aggregateByKey(参数1)(参数2,参数3)
过程:对于data的某个key,参数1为初始化值,在参数2的函数中,初始值和该key的每一个value传入函数进行操作,所有返回的结果在参数3中进行规约。
scala.collection.mutable.Set[(String, String)]()
new 了一个空的set集合,做为初始值
参数2
(set, item) => {
set += item
}
一个类似于map的映射函数,将该key的每一个value(在本案例之是(访问时间,访问url))作为item,将其放入set中并返回。
可知某个key的所有value都会返回一个含有该value的set
参数3
(set1, set2) => set1 union set2
该key的所有value得到的set进行union规约。并返回
最终结果:得到了每一个用户在所有时间的访问url的行为信息。