创建推荐模型上传hdfs
package cn.tedu.alsmovie
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.mllib.recommendation.Rating
import org.apache.spark.mllib.recommendation.ALS
/**
- 处理u.data 建立推荐系统模型,为编号为789号的用户推荐10部电影
*/
object Driver {
def main(args: Array[String]): Unit = {
val conf=new SparkConf().setMaster("local").setAppName("alsmovie")
val sc=new SparkContext(conf)
val data=sc.textFile("c://data/ml/u.data", 4)
//--读取电影信息文件
val movieData=sc.textFile("c://data/ml/u.item",4)
//--RDD[String:line]->RDD[(movieId(key),movieName(value))]->collectAsMap->Map
val movieMap=movieData.map { line =>
val info=line.split("\\|")
val movieId=info(0).toInt
val movieName=info(1)
(movieId,movieName)
}.collectAsMap
val ratings=data.map { line =>
val info=line.split("\t")
val userId=info(0).toInt
val movieId=info(1).toInt
val score=info(2).toDouble
Rating(userId,movieId,score)
}
//--隐藏因子数K,建议在10~50 不易过大。k越大,底层的计算代价越大
val model=ALS.train(ratings, 50, 10, 0.01)
//--为789号用户推荐10个电影
val u789Result=model.recommendProducts(789, 10)
.map { rat =>
//--获取用户id
val userId=rat.user
//--获取商品id
val movieid=rat.product
//--是通过movieMap 的key获取对应的value(电影名)
val movieName=movieMap(movieid)
//--获取评分
val score=rat.rating
//--返回结果
(userId,movieName,score)
}
//--检验模型推荐的准确性。本案例使用直观检验法
//--实现思路:①获取789号用户看过的所有电影
//--②根据789号用户对电影的打分,做降序排序,然后取出前10部(表示这是此用户最喜爱的前10部电影)
//--③用推荐的结果和他喜爱的电影比对,看是否有类似的
//--keyBy函数,会根据指定的匿名函数规则作为属性key来查找
//--下面表示以用户id属性为key来查找
//--lookup()指定具体的key数据
val u789Movies=ratings.keyBy { rat => rat.user}.lookup(789)
val u789Top10=u789Movies.sortBy{rat=> -rat.rating}.take(10)
.map { rat =>movieMap(rat.product)}
//--模型存储,路径可以是本地文件系统,也可以是hdfs
//--模型存储后,以后在使用时,不需要重新迭代训练,直接加载即可以使用
model.save(sc,"hdfs://hadoop01:9000/rec-result")
}
}
加载推荐模型
package cn.tedu.alsmovie
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.mllib.recommendation.MatrixFactorizationModel
/**
- 加载推荐系统模型
*/
object LoadDriver {
def cosArray(a1:Array[Double],a2:Array[Double])={
val a1a2=a1 zip a2
val a1a2Fenzi=a1a2.map{x=>x._1*x._2}.sum
val a1Fenmu=Math.sqrt(a1.map { x => x*x }.sum)
val a2Fenmu=Math.sqrt(a2.map { x => x*x }.sum)
//--返回两个向量之间夹角余弦
a1a2Fenzi/(a1Fenmu*a2Fenmu)
}
def main(args: Array[String]): Unit = {
val conf=new SparkConf().setMaster("local").setAppName("load")
val sc=new SparkContext(conf)
//--加载模型
val model=MatrixFactorizationModel.load(sc,"hdfs://hadoop01:9000/rec-result")
val u789Result=model.recommendProducts(789, 10)
//--Spark的ALS模型,只提供了基于用户的推荐(计算用户和用户之间的相似度,然后做推荐)
//--但是没有提供基于物品推荐的方法(计算物品和物品之间的相似度,然后做推荐),需要自己实现
//--场景:某个用户看了 123号电影。要求系统推荐10部电影
//--实现思路:核心是计算出其他电影和123号电影之间的相似度
//--①获取模型的物品因子矩阵
//--②获取123号电影的因子数组
//--③分别计算其他电影和123号电影的相似度(使用向量之间的夹角余弦来计算)
//--④根据相似度降序排序,取出前10部
//--获取用户的因子矩阵,本案例不需要
val userFeatures=model.userFeatures
//--获取物品因子矩阵,可以通过此因子矩阵计算出 电影-电影之间的相似度
//--RDD[(电影id,电影的因子数组)]
val movieFeatures=model.productFeatures
//--以电影id属性为key,具体找123号电影的数据
val movie123Features=movieFeatures.keyBy{x=>x._1}.lookup(123).head._2
val result=movieFeatures.map{case(movieId,feature)=>
//--计算当前电影和123号电影之间的相似度
val cos=cosArray(movie123Features, feature)
//--返回(当前电影id,和123号电影计算后的相似度)
(movieId,cos)
}
//--推荐前10部电影
val top10=result.sortBy{x=> -x._2}.take(11).drop(1)
top10.foreach{println}
}
}