电影推荐系统-[离线统计部分](二)创建Package、类+编写代码 (3)【按类别统计平均分最高的10个电影】
Posted on 2020-09-20 09:46 MissRong 阅读(187) 评论(0) 收藏 举报电影推荐系统-[离线统计部分](二)创建Package、类+编写代码
3)按类别统计平均分最高的10个电影
(1)电影流程图

(2)求Top10的大致思路
平均分表 join 电影表 得到 电影表带平均分
带平均分的电影表 笛卡儿积 所有的类别---》 过滤掉不包含的类别 ---》group by 得到数据形式:[类别,评分(mid,A ),(mid,B),(mid,C),(mid ,D)]
(3)Scala代码:
自定数据类
package staticRecommender
/**
* @Author : ASUS and xinrong
* @Version : 2020/9/4
* 数据格式转换类
* ---------------电影表------------------------
* 1
* Toy Story (1995)
*
* 81 minutes
* March 20, 2001
* 1995
* English
* Adventure|Animation|Children|Comedy|Fantasy
* Tom Hanks|Tim Allen|Don Rickles|Jim Varney|Wallace Shawn|John Ratzenberger|Annie Potts|John Morris|Erik von Detten|Laurie Metcalf|R. Lee Ermey|Sarah Freeman|Penn Jillette|Tom Hanks|Tim Allen|Don Rickles|Jim Varney|Wallace Shawn
* John Lasseter
*/
case class Movie(val mid:Int,val name:String,val descri:String,
val timelong:String,val cal_issue:String,val shoot:String,
val language:String,val genres :String,val actors:String,val directors:String)
/**
* -----用户对电影的评分数据集--------
* 1,31,2.5,1260759144
*/
case class Rating(val uid:Int,val mid:Int,val score:Double,val timastamp:Int)
/**
* --------用户对电影的标签数据集--------
* 15,339,sandra 'boring' bullock,1138537770
*/
case class Tag(val uid:Int,val mid:Int,val tag:String,val timestamp:Int)
/**
*
* MongoDB配置对象
* @param uri
* @param db
*/
case class MongoConfig(val uri:String,val db:String)
/**
* ES配置对象
* @param httpHosts
* @param transportHosts:保存的是所有ES节点的信息
* @param clusterName
*/
case class EsConfig(val httpHosts:String,val transportHosts:String,val index:String,val clusterName:String)
/**
* recs的二次封装数据类
* @param mid
* @param res
*/
case class Recommendation(mid:Int,res:Double)
/**
* Key-Value封装数据类
* @param genres
* @param recs
*/
case class GenresRecommendation(genres:String,recs:Seq[Recommendation])
实际执行类
//三、按类别统计平均分最高的10个电影(第4个目标包含第3个目标)
//可以将Movie当作参数直接传进来,也可以将movies当成视图去写
//在学闭包柯里化的时候(柯里化解决了多个参数的问题)--可以将多个参数拆成多个括号的形式,调用的时候需要注意-要写多个括号
def genresTop10(spark:SparkSession)(movies:Dataset[Movie])(implicit mongoConfig: MongoConfig):Unit={
//1.定义所有电影类别
val genres = List("Action","Adventure","Animation","Comedy","Ccrime","Documentary","Drama","Family","Fantasy","Foreign","History","Horror","Music","Mystery"
,"Romance","Science","Tv","Thriller","War","Western")
//2.统计电影平均分-averageMovieScore(DataFrame类型的)
val averageMovieScore=spark.sql("select mid,avg(score) as avg from ratings group by mid").cache()
//3.统计类别中分数最高的10部电影
//将电影平均分、电影两个表进行Join得到一个合并后的表
//第一个表的mid等于第二个表的mid
val moviesWithScoreDF=movies.join(averageMovieScore,Seq("mid","mid")).select("mid","avg","genres").cache()
//4.做笛卡儿积、Filter、模式匹配-GroupBy、排序+take
//1)genres一开始是一个List,将其转成RDD才能使用
val genresRDD=spark.sparkContext.makeRDD(genres)
//2)操作笛卡儿积注意引入(需要的时候再引)
import spark.implicits._
//3)进行Filter(将名字转换成小写)
//注意要将合并后的表-moviesWithScoreDF转换成RDD形式
val genresTopMovies=genresRDD.cartesian(moviesWithScoreDF.rdd).filter{
//geners:是指做笛卡儿积之后所得表的genres列;row则是指此表中属于原合并表(moviesWithScoreDF)的每行数据
case(genres,row)=>{
//如果geners在row中geners包括的电影种类里,就返回true,它就被保留了
//否则此行数据就会被清除(不删除结构,只是删除数据)
row.getAs[String]("genres").toLowerCase.contains(genres.toLowerCase)
}
}.map{
//4)GroupBy
case(genres,row)=>{
//genres作为Key,(Int,Double)作为value
(genres,(row.getAs[Int]("mid"),row.getAs[Double]("avg")))
}
}.groupByKey()
.map{
//5)排序+take
case(genres,items)=>{
//将items从Iterable转换成List,然后进行遍历
//用第二位-平均分进行排序
GenresRecommendation(genres,items.toList.sortWith(_._2>_._2).take(10).map(x=>Recommendation(x._1,x._2))) //取前10位
}
}.toDF //注意:调用toDF,需要引入:import spark.implicits._
//5.将统计好的top10电影数据写入到MongoDB里面(注意转换成DataFrame的类型)
genresTopMovies
.write
.option("uri",mongoConfig.uri)
.option("collection",GENRES_TOP_MOVIES)
.mode("overwrite")
.format("com.mongodb.spark.sql")
.save()
//6.将统计好的电影平均分写入MongoDB里面
averageMovieScore
.write
.option("uri",mongoConfig.uri)
.option("collection",AVERAGE_MOVIES_SCORE)
.mode("overwrite")
.format("com.mongodb.spark.sql")
.save()
}
调用类
//七、按类别统计平均分最高的10个电影(第4个目标包含第3个目标)
StatisticsRecommender.genresTop10(spark)(movies)
(3)启动MongoDB、执行程序、打开Robo可视化工具查看

浙公网安备 33010602011771号