Spark快速上手(5)Spark核心编程-RDD转换算子案例实操
RDD转换算子案例实操
数据准备
agent.log:时间戳,省份,城市,用户,广告【中间字段使用空格分隔】
1516609143867 6 7 64 16
1516609143869 9 4 75 18
1516609143869 1 7 87 12
1516609143869 2 8 92 9
1516609143869 6 7 84 24
1516609143869 1 8 95 5
1516609143869 8 1 90 29
需求描述
统计出每一个省份每个广告被点击数量排行的Top3
需求分析
- 每一个城市——分组
- 每个广告——分组
- 每个广告被点击的数量——聚合(求和)
- 排行Top3——降序排序,取前三
功能实现
code
def main(args: Array[String]): Unit = {
val tester: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Tester")
val sparkContext: SparkContext = new SparkContext(tester)
// data
val source: RDD[String] = sparkContext.textFile("input/agent.log")
// 转换 : (6,16) => ((6,16),1)
val mapRDD: RDD[((String, String), Int)] = source.map {
line => {
val fields: Array[String] = line.split(" ")
val province: String = fields(1)
val ads: String = fields(4)
((province, ads), 1)
}
}
// 广告单例聚合 : ((6,16),1) => ((6,16),n)
val reduceByKeyRDD: RDD[((String, String), Int)] = mapRDD.reduceByKey(_ + _)
// 广告省份分组
// (4,CompactBuffer(((4,12),25), ((4,25),11), ((4,27),13), ((4,13),21), ((4,8),21), ((4,1),20), ((4,6),15),
// ((4,7),7), ((4,3),15), ((4,22),18), ((4,10),10), ((4,19),10), ((4,9),19), ((4,23),18), ((4,18),17),
// ((4,11),11), ((4,28),16), ((4,26),10), ((4,2),22), ((4,29),13), ((4,17),14), ((4,16),22),
// ((4,5),14), ((4,21),17), ((4,0),14), ((4,15),17), ((4,24),18), ((4,4),17), ((4,20),11), ((4,14),18)))
val groupByRDD: RDD[(String, Iterable[((String, String), Int)])] = reduceByKeyRDD.groupBy(_._1._1)
// 降序排序取值 (4,List(((4,12),25), ((4,2),22), ((4,16),22)))
val sortedRDD: RDD[(String, List[((String, String), Int)])] = groupByRDD.mapValues {
iter => {
iter.toList.sortBy(_._2)(Ordering.Int.reverse).take(3)
}
}
sortedRDD.take(10).foreach(println)
}
result
(4,List(((4,12),25), ((4,2),22), ((4,16),22)))
(8,List(((8,2),27), ((8,20),23), ((8,11),22)))
(6,List(((6,16),23), ((6,24),21), ((6,22),20)))
(0,List(((0,2),29), ((0,24),25), ((0,26),24)))
(2,List(((2,6),24), ((2,21),23), ((2,29),20)))
(7,List(((7,16),26), ((7,26),25), ((7,1),23)))
(5,List(((5,14),26), ((5,21),21), ((5,12),21)))
(9,List(((9,1),31), ((9,28),21), ((9,0),20)))
(3,List(((3,14),28), ((3,28),27), ((3,22),25)))
(1,List(((1,3),25), ((1,6),23), ((1,5),22)))
thinking
- 由题目可知,我们只需要字段1、4的数据,它们分别代表省份和广告。
- 因为最后结果是需要点击的排行,所以需要统计每个广告的点击数。
- 分析数据可知,每条(line)数据代表对应的广告点击一次,故联想wordcount案例,
先将所有需要的数据转换为(_,1)格式,再用聚合算子累加获得单例广告的总点击数。
由于所需数据涉及省份和广告,故以(省份,广告)为key进行reduceByKey聚合较为合适。
所以进行map转换时,将数据转为((省份,广告),1)格式。至此广告单例点击数统计完毕。 - 由于需要每个省份都进行排名,所以先对众多广告单例根据省份进行分组,由源数据
((省份,广告),1)格式可知,省份对应索引为(_._1._1)。 - 最后,对分组完的数据(k-v类型)按照value值中的点击数(_._2)进行降序排序各个分
组中的数据即可。针对k-v类型数据中的value部分数据,应使用mapValue算子。但由于
value部分是一个迭代器,不可以直接对其进行排序,故需要将其先转为List类型。而
sortBy排序默认为升序,所以还需要设置(Ordering.Int.reverse)令其降序。最后对
排序好的数据取前三条即可。