零、本节学习目标
- 利用RDD计算总分与平均分
- 利用RDD统计每日新增用户
- 利用RDD实现分组排行榜
一、利用RDD计算总分与平均分
(一)提出任务
- 针对成绩表,计算每个学生总分和平均分
(二)准备工作
1、启动HDFS服务
- 执行命令:
start-dfs.sh
2、启动Spark服务
- 进入Spark的
sbin
目录执行命令:./start-all.sh
3、在本地创建成绩文件
- 在
/home
里创建scores.txt
文件
4、将成绩文件上传到HDFS
- 在HDFS上创建
/scoresumavg/input
目录,将成绩文件上传至该目录
(三)实现步骤
1、打开RDD项目
SparkRDDDemo
2、创建计算总分平均分对象
- 在
net.huawei.rdd
包里创建day07
子包,然后在子包里创建CalculateSumAvg
对象
package net.zyf.rdd.day07
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable.ListBuffer
/**
* 功能:统计总分与平均分
* 作者:zyf
* 日期:2023年05月11日
*/
object CalculateSumAvg {
def main(args: Array[String]): Unit = {
// 创建Spark配置对象
val conf = new SparkConf()
.setAppName("CalculateSumAvg") // 设置应用名称
.setMaster("local[*]") // 设置主节点位置(本地调试)
// 基于Spark配置对象创建Spark容器
val sc = new SparkContext(conf)
// 读取成绩文件,生成RDD
val lines = sc.textFile("hdfs://master:9000/scoresumavg/input/scores.txt")
// 定义二元组成绩列表
val scores = new ListBuffer[(String, Int)]()
// 遍历lines,填充二元组成绩列表
lines.collect.foreach(line => {
val fields = line.split(" ")
scores.append(Tuple2(fields(0), fields(1).toInt))
scores.append(Tuple2(fields(0), fields(2).toInt))
scores.append(Tuple2(fields(0), fields(3).toInt))
})
// 基于二元组成绩列表创建RDD
val rdd = sc.makeRDD(scores)
// 对rdd按键归约得到rdd1,计算总分
val rdd1 = rdd.reduceByKey(_ + _)
// 将rdd1映射成rdd2,计算总分与平均分
val rdd2 = rdd1.map(score => (score._1, score._2, (score._2 / 3.0).formatted("%.2f")))
// 在控制台输出rdd2的内容
rdd2.collect.foreach(println)
// 将rdd2内容保存到HDFS指定位置
rdd2.saveAsTextFile("hdfs://master:9000/scoresumavg/output")
}
}
3、运行程序,查看结果
- 运行程序
CalculateSumAvg
,控制台结果
查看HDFS的结果文件
准备文件
将用户文件上传到HDFS指定位置
三、完成任务
(四)完成任务
1、在Spark Shell里完成任务
- 执行命令:
val rdd1 = sc.textFile("hdfs://master:9000/newusers/input/users.txt")
2、倒排
(3)倒排后的RDD按键分组
- 执行命令:
val rdd3 = rdd2.groupByKey()
(4)取分组后的日期集合最小值,计数为1
- 执行命令:
val rdd4 = rdd3.map(line => (line._2.min, 1))
(5)按键计数,得到每日新增用户数
- 执行命令:
val result = rdd4.countByKey()
执行命令:result.keys.foreach(key => println(key + "新增用户:" + result(key)))
(6)让输出结果按日期升序
- 映射不能直接排序,只能让键集转成列表之后先排序,再遍历键集输出映射
- 执行命令:
val keys = result.keys.toList.sorted
,让键集升序排列
2、在IntelliJ IDEA里完成任务
SparkRDDDemo
(2)创建统计新增用户对象
- 在
net.huawei.day07
包里创建CountNewUsers
对象
package net.zyf.rdd.day07
import org.apache.spark.{SparkConf, SparkContext}
/**
* 功能:统计新增用户
* 作者:zyf
* 日期:2023年05月15日
*/
object CountNewUsers {
def main(args: Array[String]): Unit = {
// 创建Spark配置对象
val conf = new SparkConf()
.setAppName("CountNewUsers") // 设置应用名称
.setMaster("local[*]") // 设置主节点位置(本地调试)
// 基于Spark配置对象创建Spark容器
val sc = new SparkContext(conf)
// 读取文件,得到RDD
val rdd1 = sc.textFile("hdfs://master:9000/newusers/input/users.txt")
// 倒排,互换RDD中元组的元素顺序
val rdd2 = rdd1.map(
line => {
val fields = line.split(",")
(fields(1), fields(0))
}
)
// 倒排后的RDD按键分组
val rdd3 = rdd2.groupByKey()
// 取分组后的日期集合最小值,计数为1
val rdd4 = rdd3.map(line => (line._2.min, 1))
// 按键计数,得到每日新增用户数
val result = rdd4.countByKey()
// 让统计结果按日期升序
val keys = result.keys.toList.sorted
keys.foreach(key => println(key + "新增用户:" + result(key)))
// 停止Spark容器
sc.stop()
}
}
(3)运行程序,查看结果
- 运行程序
CountNewUsers
,控制台结果
三、利用RDD实现分组排行榜
(一)提出任务
- 分组求TopN是大数据领域常见的需求,主要是根据数据的某一列进行分组,然后将分组后的每一组数据按照指定的列进行排序,最后取每一组的前N行数据。
- 有一组学生成绩数据
(二)实现思路
- 使用Spark RDD的
groupByKey()
算子可以对(key, value)
形式的RDD按照key进行分组,key相同的元素的value将聚合到一起,形成(key, value-list)
,将value-list
中的元素降序排列取前N个即可。
(三)准备工作
1、在本地创建成绩文件
- 在
/home
目录里创建grades.txt
文件
2、将成绩文件上传到HDFS上指定目录
- 将
grades.txt
上传到HDFS的/topn/input
目录
(四)完成任务
1、在Spark Shell里完成任务
- 执行命令:
val lines = sc.textFile("hdfs://master:9000/topn/input/grades.txt")
(2)利用映射算子生成二元组构成的RDD
val grades = lines.map(line => {
val fields = line.split(" ")
(fields(0), fields(1))
})
grades.collect.foreach(println)
(3)按键分组得到新的二元组构成的RDD
- 执行命令:
val groupGrades = grades.groupByKey()
(4)按值排序,取前三
val top3 = groupGrades.map(item => {
val name = item._1
val top3 = item._2.toList.sortWith(_ > _).take(3)
(name, top3)
})
top3.collect.foreach(println)
(5)按指定格式输出结果
top3.collect.foreach(line => {
val name = line._1
var scores = ""
line._2.foreach(score => scores = scores + " " + score)
println(name + ":" + scores)
})
2、在IntelliJ IDEA里完成任务
SparkRDDDemo
(2)创建分组排行榜单例对象
- 在
net.huawei.rdd.day07
包里创建GradeTopN
单例对象
package net.zyf.rdd.day07
import org.apache.spark.{SparkConf, SparkContext}
/**
* 功能:成绩分组排行榜
* 作者:zyf
* 日期:2023年05月11日
*/
object GradeTopN {
def main(args: Array[String]): Unit = {
// 创建Spark配置对象
val conf = new SparkConf()
.setAppName("GradeTopN") // 设置应用名称
.setMaster("local[*]") // 设置主节点位置(本地调试)
// 基于Spark配置对象创建Spark容器
val sc = new SparkContext(conf)
// 实现分组排行榜
val top3 = sc.textFile("hdfs://master:9000/topn/input/grades.txt")
.map(line => {
val fields = line.split(" ")
(fields(0), fields(1))
}) // 将每行成绩映射成二元组(name, grade)
.groupByKey() // 按键分组
.map(item => {
val name = item._1
val top3 = item._2.toList.sortWith(_ > _).take(3)
(name, top3)
}) // 值排序,取前三
// 输出分组排行榜结果
top3.collect.foreach(line => {
val name = line._1
var scores = ""
line._2.foreach(score => scores = scores + " " + score)
println(name + ":" + scores)
})
// 停止Spark容器,结束任务
sc.stop()
}
}
(3)运行程序,查看结果
- 在控制台查看输出结果