电影推荐系统-[离线推荐部分](二)写代码(4)【离线推荐整体代码展示】
自定义类:
package offlineRecommender /** * @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 MovieRating(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]) //注:Seq-Sequence是一个特质,Recommendation是一个实现类 case class UserRecs(uid:Int,recs:Seq[Recommendation])
具体实现类:
package offlineRecommender import org.apache.spark.SparkConf import org.apache.spark.mllib.recommendation.{ALS, Rating} import org.apache.spark.sql.SparkSession /** * @Author : ASUS and xinrong * @Version : 2020/9/20 * 离线推荐算法 */ object OfflineRecommender { //声明要用到的表 val MONGODB_RATING_COLLECTION="Rating" val MONGODB_MOVIE_COLLECTIN="Movie" val MONGODB_USER_RECS="UserRecs" //将要取前几位的数量定义成常量,便于修改 val USER_MAXRECOMMENDATION=10 def main(args: Array[String]): Unit = { val conf=Map( "spark.core"->"local[2]", "mongo.uri"->"mongodb://192.168.212.21:27017/recom", "mongo.db"->"recom" ) //1.创建Spark运行的环境(第二种创建环境的表现形式),还有一种参考:https://www.cnblogs.com/liuxinrong/articles/13698745.html
//因为涉及到计算,所以这里设置一下executor的内存的大小和driver的内存大小 val sparkConf=new SparkConf().setAppName("OfflineRecommender").setMaster(conf("spark.core")) .set("spark.executor.memory","6G") .set("spark.driver.memory","2G") val spark=SparkSession.builder().config(sparkConf).getOrCreate() //2.获取MongoDB中的数据 import spark.implicits._ //1)获取MongoDB的连接信息 val mongoConfig=MongoConfig(conf("mongo.uri"),conf("mongo.db")) //2)获取数据 //将DataFrame数据转换成RDD数据,需要先.as[Rating]再.rdd() //(1)获取Rating的数据 val ratingRDD=spark .read .option("uri",mongoConfig.uri) .option("collection",MONGODB_RATING_COLLECTION) .format("com.mongodb.spark.sql") .load() .as[MovieRating] .rdd .map(rating =>(rating.uid,rating.mid,rating.score)) .cache() //(2)获取Movie的数据 val movieRDD=spark .read .option("uri",mongoConfig.uri) .option("collection",MONGODB_MOVIE_COLLECTIN) .format("com.mongodb.spark.sql") .load() .as[Movie] .rdd .map(_.mid) .cache() //3.训练ALS(Alternatingleast squares)-交替最小二乘法模型 /** * ALS模型需要4个参数 * 1)trainData-训练数据:Rating对象的RDD,包含用户ID、物品ID,偏好值 * 2)Rank-特征维度:50 * 3)Iterations-迭代次数:5次(根据自己的算力和用户需求来设置) * 4)Lambda-跨度:0.01 */ //1)构建训练数据集 //下面这行中的Rating是Spark Mllib里面提供的-包含三种数据如下: // userId-用户ID、product-物品ID、rating-偏好值(他们三个统一在一起就成为Rating) val trainData=ratingRDD.map(x=>Rating(x._1,x._2,x._3)) // val rank=50 //定义维度 // val iterations=5 //定义迭代次数 // val lambna=0.01 //设置跨度 //如果有多个数据,建议用元组的方式将他们钉在一起 val(rank,iteration,lambna)=(50,5,0.01) //这样更方便 val model= ALS.train(trainData,rank,iteration,lambna) //2)计算用户推荐矩阵 val userRDD=ratingRDD.map(_._1).distinct().cache() //将 含有所有用户名的表 和 含有所有电影名的表 做笛卡儿积 val userMovies=userRDD.cartesian(movieRDD) //连带模型和做好笛卡儿积之后的表得出预测数据 val preRatings=model.predict(userMovies) //4.将数据写入MongoDB //1)Filter--将相关性强的数据写入,这里就是将偏好值大于0的数据写入 val userRecs= preRatings .filter(_.rating > 0) //Spark Mllib 提供的Rating是RDD类型的,这里将其转换成Double类型的 //用户ID-user作为Key,(物品ID-product、偏好值-rating)作为value //rating123就是preRatings里面的Rating(注:preRatings的类型为:RDD[Rating]) .map(rating123 => (rating123.user, (rating123.product, rating123.rating))) //2)groupBy .groupByKey() //3)将数据转换成MongoDB能够接收的形式--需要自定义数据类 .map{ //在Model里面新建自定义数据类 case (uid,recs)=> UserRecs(uid,recs.toList.sortWith(_._2>_._2).take(USER_MAXRECOMMENDATION) .map(x=>Recommendation(x._1,x._2))) }.toDF() //转成DataFrame再写入MongoDB //4)写入MongoDB userRecs .write .option("uri",mongoConfig.uri) .option("collection",MONGODB_USER_RECS) .mode("overwrite") .format("com.mongodb.spark.sql") .save() //5.关闭Spark spark.close() } }
                    
                
                
            
        
浙公网安备 33010602011771号