利用Spark MLlib中的协同过滤算法完成针对特定用户的电影推荐功能,并将推荐结果保存到MySQL数据库中。
https://grouplens.org/datasets/movielens/
创建一个rating类和parseRating函数。parseRating把读取的ratings数据集中的每一行,并转化成Rating类的对象。
主要代码:
def parseRating(str: String): Rating = {
val fields = str.split("::")
assert(fields.size == 4)
Rating(fields(0).toInt, fields(1).toInt, fields(2).toFloat, fields(3).toLong)
}
def main(args: Array[String]): Unit = {
val sc=SparkSession.builder()
.master("local")
.appName("movie")
.getOrCreate()
val ratingRDD=sc.sparkContext.textFile("/usr/cx/ratings.dat")
//将RDD数据转化成DataFrame数据
val ratings=sc.createDataFrame(ratingRDD.map(parseRating))
// ratings.show()
把ratings数据集划分训练集和测试集,其中训练集占80%,测试集占20%。
主要代码:
//将样本8-2分成训练样本和测试样本
val Array(training, test) = ratings.randomSplit(Array(0.8, 0.2))
使用ALS来建立模型。这里构建两个模型,一个是显性反馈,另一个是隐性反馈。
主要代码:
//协同过滤,训练模型
val alsExplicit = new ALS()
.setMaxIter(5) //迭代次数,用于最小二乘交替迭代的次数
.setRegParam(0.01) //惩罚系数
.setUserCol("userId")
.setItemCol("movieId")
.setRatingCol("rating") //显示评分得到的矩阵形式
val alsImplicit = new ALS()
.setMaxIter(5) //迭代次数,用于最小二乘交替迭代的次数
.setRegParam(0.01) //惩罚系数
.setImplicitPrefs(true)
.setUserCol("userId")
.setItemCol("movieId")
.setRatingCol("rating") //显示评分得到的矩阵形式
把推荐模型放在训练数据上训练。
主要代码:
val modelExplicit = alsExplicit.fit(training)
val modelImplicit = alsImplicit.fit(training)
对训练集中的用户电影进行预测,得到预测评分的数据集。计算模型的均方根误差。
主要代码:
//得到预测评分的测试集
val predictionsExplicit = modelExplicit.transform(test).na.drop()
val predictionsImplicit = modelImplicit.transform(test).na.drop()
// predictionsExplicit.show()
// predictionsImplicit.show()
//计算模型均方根误差
val evaluator = new RegressionEvaluator()
.setMetricName("rmse")
.setLabelCol("rating")
.setPredictionCol("prediction")
val rmseExplicit = evaluator.evaluate(predictionsExplicit)
val rmseImplicit = evaluator.evaluate(predictionsImplicit)
println(s"Explicit:模型均方根误差 : $rmseExplicit")
println(s"Implicit:模型均方根误差 : $rmseImplicit")
对输入的用户进行预测,并将结果存入数据库。
主要代码:
println("请输入用户id:")
val userId:Int=StdIn.readInt()
val movieDF=ratings.where(s"userId= $userId")
println(s"为id为 $userId 的用户推荐如下10部电影:")
movieDF.limit(10).show()
val df=movieDF.limit(10)
//将数据存到数据库中
val prop=new Properties()
prop.put("user","root")
prop.put("password","XXXXX")
prop.put("driver","com.mysql.jdbc.Driver")
df.write.mode("Overwrite").jdbc("jdbc:mysql://localhost:3306/movies","movies.ratings",prop)
import org.apache.spark.ml.evaluation.RegressionEvaluator
import org.apache.spark.ml.recommendation.ALS
import org.apache.spark.sql.SparkSession
import java.util.Properties
import scala.io.StdIn
object movie {
case class Rating(userId: Int, movieId: Int, rating: Float, timestamp: Long)
//将ratings数据集中的每一行转化为Rating对象
def parseRating(str: String): Rating = {
val fields = str.split("::")
assert(fields.size == 4)
Rating(fields(0).toInt, fields(1).toInt, fields(2).toFloat, fields(3).toLong)
}
def main(args: Array[String]): Unit = {
val sc=SparkSession.builder()
.master("local")
.appName("movie")
.getOrCreate()
val ratingRDD=sc.sparkContext.textFile("/usr/cx/ratings.dat")
//将RDD数据转化成DataFrame数据
val ratings=sc.createDataFrame(ratingRDD.map(parseRating))
// ratings.show()
//将样本8-2分成训练样本和测试样本
val Array(training, test) = ratings.randomSplit(Array(0.8, 0.2))
//协同过滤,训练模型
val alsExplicit = new ALS()
.setMaxIter(5) //迭代次数,用于最小二乘交替迭代的次数
.setRegParam(0.01) //惩罚系数
.setUserCol("userId")
.setItemCol("movieId")
.setRatingCol("rating") //显示评分得到的矩阵形式
val alsImplicit = new ALS()
.setMaxIter(5) //迭代次数,用于最小二乘交替迭代的次数
.setRegParam(0.01) //惩罚系数
.setImplicitPrefs(true)
.setUserCol("userId")
.setItemCol("movieId")
.setRatingCol("rating") //显示评分得到的矩阵形式
val modelExplicit = alsExplicit.fit(training)
val modelImplicit = alsImplicit.fit(training)
//得到预测评分的测试集
val predictionsExplicit = modelExplicit.transform(test).na.drop()
val predictionsImplicit = modelImplicit.transform(test).na.drop()
// predictionsExplicit.show()
// predictionsImplicit.show()
//计算模型均方根误差
val evaluator = new RegressionEvaluator()
.setMetricName("rmse")
.setLabelCol("rating")
.setPredictionCol("prediction")
val rmseExplicit = evaluator.evaluate(predictionsExplicit)
val rmseImplicit = evaluator.evaluate(predictionsImplicit)
println(s"Explicit:模型均方根误差 : $rmseExplicit")
println(s"Implicit:模型均方根误差 : $rmseImplicit")
println("请输入用户id:")
val userId:Int=StdIn.readInt()
val movieDF=ratings.where(s"userId= $userId")
println(s"为id为 $userId 的用户推荐如下10部电影:")
movieDF.limit(10).show()
val df=movieDF.limit(10)
//将数据存到数据库中
val prop=new Properties()
prop.put("user","root")
prop.put("password","XXXXX")
prop.put("driver","com.mysql.jdbc.Driver")
df.write.mode("Overwrite").jdbc("jdbc:mysql://localhost:3306/movies","movies.ratings",prop)
}
}