网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
需求2: 查找每个电影类别及其对应的平均评分
需求3: 查找被评分次数较多的前十部电影
数据介绍:使用的文件movies.csv和ratings.csv
movies.csv该文件是电影数据,对应的为维表数据,其数据格式为
movieId title genres
电影id 电影名称 电影所属分类
样例数据如下所示:逗号分隔
1,Toy Story (1995),Adventure|Animation|Children|Comedy|Fantasy
ratings.csv该文件为定影评分数据,其数据格式为
userId movieId rating timestamp
电影id 电影名称 电影所属分类 时间戳
建表语句
CREATE DATABASE db_movies;
USE db_movies;
CREATE TABLE `ten_movies_avgrating` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
`movieId` int(11) NOT NULL COMMENT '电影id',
`ratingNum` int(11) NOT NULL COMMENT '评分个数',
`title` varchar(100) NOT NULL COMMENT '电影名称',
`avgRating` decimal(10,2) NOT NULL COMMENT '平均评分',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `movie_id_UNIQUE` (`movieId`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `genres_average_rating` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
`genres` varchar(100) NOT NULL COMMENT '电影类别',
`avgRating` decimal(10,2) NOT NULL COMMENT '电影类别平均评分',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `genres_UNIQUE` (`genres`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `ten_most_rated_films` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
`movieId` int(11) NOT NULL COMMENT '电影Id',
`title` varchar(100) NOT NULL COMMENT '电影名称',
`ratingCnt` int(11) NOT NULL COMMENT '电影被评分的次数',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
项目结构一览图
由题意可知
先创建实体类,字段是从建表语句中得来的。
Entry.scala
package cn.movies.Packet
/\*\*
\* @author ChinaManor
\* #Description Entry
\* #Date: 6/6/2021 17:23
\*/
object Entry {
case class Movies(
movieId: String, // 电影的id
title: String, // 电影的标题
genres: String // 电影类别
)
case class Ratings(
userId: String, // 用户的id
movieId: String, // 电影的id
rating: String, // 用户评分
timestamp: String // 时间戳
)
// 需求1MySQL结果表
case class tenGreatestMoviesByAverageRating(
movieId: String, // 电影的id
ratingNum:String,
title: String, // 电影的标题
avgRating: String // 电影平均评分
)
// 需求2MySQL结果表
case class topGenresByAverageRating(
genres: String, //电影类别
avgRating: String // 平均评分
)
// 需求3MySQL结果表
case class tenMostRatedFilms(
movieId: String, // 电影的id
title: String, // 电影的标题
ratingCnt: String // 电影被评分的次数
)
}
再创建个表结构~~
Schema.scala
package cn.movies.Packet
import org.apache.spark.sql.types.{DataTypes, StructType}
/\*\*
\* @author ChinaManor
\* #Description Schema
\* #Date: 6/6/2021 17:34
\*/
object Schema {
class SchemaLoader {
// movies数据集schema信息
private val movieSchema = new StructType()
.add("movieId", DataTypes.StringType, false)
.add("title", DataTypes.StringType, false)
.add("genres", DataTypes.StringType, false)
// ratings数据集schema信息
private val ratingSchema = new StructType()
.add("userId", DataTypes.StringType, false)
.add("movieId", DataTypes.StringType, false)
.add("rating", DataTypes.StringType, false)
.add("timestamp", DataTypes.StringType, false)
def getMovieSchema: StructType = movieSchema
def getRatingSchema: StructType = ratingSchema
}
}
然后开始写Main方法,其实只有区区八十行代码。。。
spark总要有实例对象吧。
// 创建spark session
val spark = SparkSession
.builder
.appName(this.getClass.getSimpleName.stripSuffix("$"))
.master("local[4]")
.getOrCreate
然后 new个schema信息
val schemaLoader = new SchemaLoader
然后尝试读取csv文件,
// 读取Movie数据集
val movieDF: DataFrame = readCsvIntoDataSet(spark, MOVIES_CSV_FILE_PATH, schemaLoader.getMovieSchema)
// 读取Rating数据集
val ratingDF: DataFrame = readCsvIntoDataSet(spark, RATINGS_CSV_FILE_PATH, schemaLoader.getRatingSchema)
发现读取方法和路径都没有,于是补救一下
// 文件路径
private val MOVIES_CSV_FILE_PATH = "D:\\Users\\Administrator\\Desktop\\exam0601\\datas\\movies.csv"
private val RATINGS_CSV_FILE_PATH = "D:\\Users\\Administrator\\Desktop\\exam0601\\datas\\ratings.csv"
/**
* 读取数据文件,转成DataFrame
*
* @param spark
* @param path
* @param schema
* @return
*/
def readCsvIntoDataSet(spark: SparkSession, path: String, schema: StructType) = {
val dataDF: DataFrame = spark.read
.format("csv")
.option("header", "true")
.schema(schema)
.load(path)
dataDF
}
紧接着重头戏来了。。
写sql语句,在大数据行业懂得写sql就等于会了80%
WITH ratings_filter_cnt AS (
SELECT
movieId,
count( \* ) AS rating_cnt,
Round(avg( rating ),2) AS avg_rating
FROM
ratings
GROUP BY
movieId
HAVING
count( \* ) >= 50
),
ratings_filter_score AS (
SELECT
movieId, -- 电影id
rating_cnt, -- 个数
avg_rating -- 电影平均评分
FROM ratings_filter_cnt
ORDER BY avg_rating DESC -- 平均评分降序排序
LIMIT 10 -- 平均分较高的前十部电影
)
SELECT
m.movieId,
r.rating_cnt AS ratingNum,
m.title,
r.avg_rating AS avgRating
FROM
ratings_filter_score r
JOIN movies m ON m.movieId = r.movieId ORDER BY r.avg_rating DESC
关键点在于
WITH XXX AS SELECT
最后保存写入mysql表中
def saveToMysql(reportDF: DataFrame) = {
// TODO: 使用SparkSQL提供内置Jdbc数据源保存数据
reportDF
.coalesce(1)
.write


**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化资料的朋友,可以戳这里获取](https://gitee.com/vip204888)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**