目录
零、本讲学习目标
一、使用Spark SQL实现词频统计
(一)提出任务
(二)实现任务
1、准备数据文件
2、创建Maven项目
3、修改源程序目录
4、添加依赖和设置源程序目录
5、创建日志属性文件
6、创建HDFS配置文件
7、创建词频统计单例对象
8、启动程序,查看结果
9、词频统计数据转化流程图
二、使用Spark SQL计算总分与平均分
(一)提出任务
(二)完成任务
1、准备数据文件
2、新建Maven项目
3、修改源程序目录
4、添加相关依赖和设置源程序目录
5、创建日志属性文件
6、创建HDFS配置文件
7、创建计算总分平均分单例对象
8、运行程序,查看结果
三、使用Spark SQL实现分组排行榜
(一)提出任务
(二)涉及知识点
1、数据集与数据帧
2、开窗函数
(三)完成任务
1、准备数据文件
2、新建Maven项目
3、修改源程序目录
4、添加相关依赖和设置源程序目录
5、创建日志属性文件
6、创建HDFS配置文件
7、创建分组排行榜单例对象
8、运行程序,查看结果
四、使用SparkSQL统计每日新增用户
(一)提出任务
(二)实现思路
(三)完成任务
1、准备数据文件
2、新建Maven项目
4、添加相关依赖和设置源程序目录
5、创建日志属性文件
6、创建HDFS配置文件
7、创建统计新增用户单例对象
8、运行程序,查看结果
9、在Spark Shell里运行代码
hello scala world
hello spark world
scala is very concise
spark is very powerful
let us learn scala and spark
we can learn them well
4.0.0
net.huawei.sql
SparkSQLWordCount
1.0-SNAPSHOT
org.scala-lang
scala-library
2.12.15
org.apache.spark
spark-core_2.12
3.1.3
org.apache.spark
spark-sql_2.12
3.1.3
src/main/scala
log4j.rootLogger=ERROR, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spark.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
only config in clients
dfs.client.use.datanode.hostname
true
package net.huawei.sql
import org.apache.spark.sql.{Dataset, SparkSession}
/**
* 功能:利用Spark SQL实现词频统计
* 作者:华卫
* 日期:2023年05月25日
*/
object WordCount {
def main(args: Array[String]): Unit = {
// 创建或得到SparkSession
val spark = SparkSession.builder()
.appName("SparkSQLWordCount")
.master("local[*]")
.getOrCreate()
// 读取HDFS上的单词文件
val lines: Dataset[String] = spark.read.textFile("hdfs://master:9000/wordcount/input/words.txt")
// 显示数据集lines内容
lines.show()
// 导入Spark会话对象的隐式转换
import spark.implicits._
// 将数据集中的数据按空格切分并合并
val words: Dataset[String] = lines.flatMap(_.split(" "))
// 显示数据集words内容
words.show()
// 将数据集默认列名由value改为word,并转换成数据帧
val df = words.withColumnRenamed("value", "word").toDF()
// 显示数据帧内容
df.show()
// 基于数据帧创建临时视图
df.createTempView("v_words")
// 执行SQL分组查询,实现词频统计
val wc = spark.sql(
"""
| select word, count(*) as count
| from v_words group by word
| order by count desc
|""".stripMargin)
// 显示词频统计结果
wc.show()
// 关闭会话
spark.close()
}
}
有多科成绩表,比如python.txt、spark.txt、django.txt,计算每个学生三科总分与平均分
Python成绩表 - python.txt
1 张三丰 89
2 李孟达 95
3 唐雨涵 92
4 王晓云 93
5 张晓琳 88
6 佟湘玉 88
7 杨文达 66
8 陈燕文 98
spark.txt
1 张三丰 67
2 李孟达 78
3 唐雨涵 89
4 王晓云 75
5 张晓琳 93
6 佟湘玉 70
7 杨文达 87
8 陈燕文 90
django.txt
1 张三丰 88
2 李孟达 93
3 唐雨涵 97
4 王晓云 87
5 张晓琳 79
6 佟湘玉 89
7 杨文达 93
8 陈燕文 95
1 张三丰 244 81.33
2 李孟达 266 88.67
3 唐雨涵 278 92.67
4 王晓云 255 85.00
5 张晓琳 260 86.67
6 佟湘玉 247 82.33
7 杨文达 246 82.00
8 陈燕文 283 94.33
4.0.0
net.huawei.sql
CalculateSumAvg
1.0-SNAPSHOT
org.scala-lang
scala-library
2.12.15
org.apache.spark
spark-core_2.12
3.1.3
org.apache.spark
spark-sql_2.12
3.1.3
src/main/scala
log4j.rootLogger=ERROR, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spark.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
only config in clients
dfs.client.use.datanode.hostname
true
package net.huawei.sql
import org.apache.spark.sql.{Dataset, SparkSession}
/**
* 功能:利用Spark SQL计算总分与平均分
* 作者:华卫
* 日期:2023年05月25日
*/
object CalculateSumAverage {
def main(args: Array[String]): Unit = {
// 创建或得到Spark会话对象
val spark = SparkSession.builder()
.appName("CalculateSumAverage")
.master("local[*]")
.getOrCreate()
// 读取HDFS上的成绩文件
val lines: Dataset[String] = spark.read.textFile("hdfs://master:9000/calsumavg/input")
// 导入隐式转换
import spark.implicits._
// 创建成绩数据集
val gradeDS: Dataset[Grade] = lines.map(
line => {
val fields = line.split(" ")
val id = fields(0).toInt
val name = fields(1)
val score = fields(2).toInt
Grade(id, name, score)
})
// 将数据集转换成数据帧
val df = gradeDS.toDF();
// 基于数据帧创建临时表
df.createOrReplaceTempView("t_grade")
// 查询临时表,计算总分与平均分
val result = spark.sql(
"""
|select first(id) as id, name, sum(score) as sum,
| cast(avg(score) as decimal(5, 2)) as average
| from t_grade
| group by name
| order by id
|""".stripMargin
)
// 按照指定格式输出总分与平均分
result.collect.foreach(row => println(row(0) + " " + row(1) + " " + row (2) + " " + row(3)))
// 关闭Spark会话
spark.close()
}
// 定义成绩样例类
case class Grade(id: Int, name: String, score: Int)
}
张三丰 90
李孟达 85
张三丰 87
王晓云 93
李孟达 65
张三丰 76
王晓云 78
李孟达 60
张三丰 94
王晓云 97
李孟达 88
张三丰 80
王晓云 88
李孟达 82
王晓云 98
张三丰:94
张三丰:90
张三丰:87
李孟达:88
李孟达:85
李孟达:82
王晓云:98
王晓云:97
王晓云:93
t_grade
SELECT * FROM t_grade tg
WHERE (SELECT COUNT(*) FROM t_grade
WHERE tg.name = t_grade.name
AND score >= tg.score
) <= 3 ORDER BY name, score DESC;
(1)开窗函数概述
Spark 1.5.x
版本以后,在Spark SQL
和DataFrame
中引入了开窗函数,其中比较常用的开窗函数就是row_number()
,该函数的作用是根据表中字段进行分组,然后根据表中的字段排序;其实就是根据其排序顺序,给组中的每条记录添加一个序号,且每组序号都是从1
开始,可利用它这个特性进行分组取topN
。(2)开窗函数格式
4.0.0
net.huawei.sql
SparkSQLGradeTopN
1.0-SNAPSHOT
org.scala-lang
scala-library
2.12.15
org.apache.spark
spark-core_2.12
3.1.3
org.apache.spark
spark-sql_2.12
3.1.3
src/main/scala
log4j.rootLogger=ERROR, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spark.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
only config in clients
dfs.client.use.datanode.hostname
true
package net.huawei.sql
import org.apache.spark.sql.{Dataset, SparkSession}
/**
* 功能:利用Spark SQL实现分组排行榜
* 作者:华卫
* 日期:2022年06月15日
*/
object GradeTopNBySQL {
def main(args: Array[String]): Unit = {
// 创建或得到Spark会话对象
val spark = SparkSession.builder()
.appName("GradeTopNBySQL")
.master("local[*]")
.getOrCreate()
// 读取HDFS上的成绩文件
val lines: Dataset[String] = spark.read.textFile("hdfs://master:9000/input/grades.txt")
// 导入隐式转换
import spark.implicits._
// 创建成绩数据集
val gradeDS: Dataset[Grade] = lines.map(
line => { val fields = line.split(" ")
val name = fields(0)
val score = fields(1).toInt
Grade(name, score)
})
// 将数据集转换成数据帧
val df = gradeDS.toDF()
// 基于数据帧创建临时表
df.createOrReplaceTempView("t_grade")
// 查询临时表,实现分组排行榜
val top3 = spark.sql(
"""
|SELECT name, score FROM
| (SELECT name, score, row_number() OVER (PARTITION BY name ORDER BY score DESC) rank from t_grade) t
| WHERE t.rank <= 3
|""".stripMargin
)
// 按指定格式输出分组排行榜
top3.foreach(row => println(row(0) + ": " + row(1)))
// 关闭Spark会话
spark.close()
}
// 定义成绩样例类
case class Grade(name: String, score: Int)
}
2023-05-01,mike
2023-05-01,alice
2023-05-01,brown
2023-05-02,mike
2023-05-02,alice
2023-05-02,green
2023-05-03,alice
2023-05-03,smith
2023-05-03,brian
2023-05-01 | mike | alice | brown |
2023-05-02 | mike | alice | green |
2023-05-03 | alice | smith | brian |
2023-05-01新增用户数:3
2023-05-02新增用户数:1
2023-05-03新增用户数:2
2023-05-01 | 2023-05-02 | 2023-05-3 | |
---|---|---|---|
mike | √ | √ | |
alice | √ | √ | √ |
brown | √ | ||
green | √ | ||
smith | √ | ||
brian | √ |
列一 | 列二 | 列三 | |
---|---|---|---|
mike | 2023-05-01 | 2023-05-02 | |
alice | 2023-05-01 | 2022-01-02 | 2022-01-03 |
brown | 2023-05-01 | ||
green | 2023-05-02 | ||
smith | 2023-05-03 | ||
brian | 2023-05-03 |
4.0.0
net.huawei.sql
SparkSQLCountNewUsers
1.0-SNAPSHOT
org.scala-lang
scala-library
2.12.15
org.apache.spark
spark-core_2.12
3.1.3
org.apache.spark
spark-sql_2.12
3.1.3
src/main/scala
log4j.rootLogger=ERROR, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spark.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
only config in clients
dfs.client.use.datanode.hostname
true
package net.huawei.sql
import org.apache.spark.sql.{Dataset, SparkSession}
/**
* 功能:使用SparkSQL统计新增用户
* 作者:华卫
* 日期:2023年05月25日
*/
object CountNewUsers {
def main(args: Array[String]): Unit = {
def main(args: Array[String]): Unit = {
// 创建或得到Spark会话对象
val spark = SparkSession.builder()
.appName("CountNewUsers")
.master("local[*]")
.getOrCreate()
// 读取HDFS上的用户文件
val ds: Dataset[String] = spark.read.textFile("hdfs://master:9000/newusers/input/users.txt")
// 导入隐式转换
import spark.implicits._
// 创建用户数据集
val userDS: Dataset[User] = ds.map(
line => {
val fields = line.split(",")
val date = fields(0)
val name = fields(1)
User(date, name)
}
)
//将数据转换成数据帧
val df = userDS.toDF()
// 创建临时表
df.createOrReplaceTempView("t_user")
// 统计每日新增用户
val result = spark.sql(
"""
|select date, count(name) as count from
| (select min(date) as date, name from t_user group by name)
|group by date
|""".stripMargin
)
// 输出统计结果
result.foreach(row => println(row(0) + "新增用户数:" + row(1)))
// 关闭Spark会话
spark.close()
}
}
//编写User样例类
case class User(date: String, name: String)
}