推荐系统-05-Spark电影推荐、评估与部署
一、新建scala项目

二、构造程序

代码如下
package xyz.pl8
import java.io.File
import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkContext, SparkConf}
import org.apache.spark.mllib.evaluation.RegressionMetrics
import org.apache.spark.mllib.recommendation.{MatrixFactorizationModel, Rating, ALS}
import org.apache.spark.rdd.RDD
import scala.util.Random
object MovieLensALS {
  //1. Define a rating elicitation function
  // Seq[Rating]
  def elicitateRating(movies: Seq[(Int, String)])={
    val prompt="Please rate the following movie(1-5(best) or 0 if not seen: )"
    println(prompt)
    val ratings= movies.flatMap{x=>
      var rating: Option[Rating] = None  //  Rating(user: Int, product: Int, rating: Double)
      var valid = false
      while(!valid){
        println(x._2+" :")
        try{
          val r = Console.readInt()
          if (r>5 || r<0){
            println(prompt)
          } else {
            valid = true
            if (r>0){
              rating = Some(Rating(0, x._1, r))
            }
          }
        } catch{
          case e:Exception => println(prompt)
        }
      }
      rating match {
        case Some(r) => Iterator(r)  // FlatMap将结构解散成元素, 这里是Rating
        case None => Iterator.empty
      }
    }
    if (ratings.isEmpty){
      error("No ratings provided!")
    } else {
      ratings
    }
  }
  //2. Define a RMSE computation function
  def computeRmse(model: MatrixFactorizationModel, data: RDD[Rating]) = {
    val prediction = model.predict(data.map(x=>(x.user, x.product)))
    val predDataJoined = prediction.map(x=> ((x.user,x.product),x.rating)).join(data.map(x=> ((x.user,x.product),x.rating))).values
    new RegressionMetrics(predDataJoined).rootMeanSquaredError
  }
  //3. Main
  def main(args: Array[String]) {
  //3.1 Setup env
    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    if (args.length !=1){
      print("Usage: movieLensHomeDir")
      sys.exit(1)
    }
    val conf = new SparkConf().setAppName("MovieLensALS")
    .set("spark.executor.memory","500m")
    val sc = new SparkContext(conf)
  //3.2 Load ratings data and know your data
  // ratings.dat 的格式 UserID::MovieID::Rating::Timestamp
    val movieLensHomeDir=args(0)
	// RDD[long, Rating]
    val ratings = sc.textFile(new File(movieLensHomeDir, "ratings.dat").toString).map {line =>
       val fields = line.split("::")
      //timestamp, user, product, rating
	  // 取模成分成10组
      (fields(3).toLong%10, Rating(fields(0).toInt, fields(1).toInt, fields(2).toDouble))
    }
	// movies.dat格式 MovieID::Title::Genres
	// Map[Int,String]
    val movies = sc.textFile(new File(movieLensHomeDir, "movies.dat").toString).map {line =>
      val fields = line.split("::")
      //movieId, movieName
      (fields(0).toInt, fields(1))
    }.collectAsMap()
    val numRatings = ratings.count()
    val numUser = ratings.map(x=>x._2.user).distinct().count()
    val numMovie = ratings.map(_._2.product).distinct().count()
    println("Got "+numRatings+" ratings from "+numUser+" users on "+numMovie+" movies.")
  //3.3 Elicitate personal rating
    // = RDD[(long,Rating) -> Array[int] -> Map[Int, long] -> Seq[(Int, long)] -> Seq[(Int,long)] ->  Seq[Int]
    val topMovies = ratings.map(_._2.product).countByValue().toSeq.sortBy(-_._2).take(50).map(_._1)
    val random = new Random(0)
	// Seq[(Int, String)]
    val selectMovies = topMovies.filter(x=>random.nextDouble() < 0.2).map(x=>(x, movies(x)))
    val myRatings = elicitateRating(selectMovies)
    val myRatingsRDD = sc.parallelize(myRatings, 1)
  //3.4 Split data into train(60%), validation(20%) and test(20%)
    val numPartitions = 10
		// 6组(即60%),并上手工输入评价
	    val trainSet = ratings.filter(x=>x._1<6).map(_._2).union(myRatingsRDD).repartition(numPartitions).persist()
    val validationSet = ratings.filter(x=>x._1>=6 && x._1<8).map(_._2).persist()
    val testSet = ratings.filter(x=>x._1>=8).map(_._2).persist()
    val numTrain = trainSet.count()
    val numValidation = validationSet.count()
    val numTest = testSet.count()
    println("Training data: "+numTrain+" Validation data: "+numValidation+" Test data: "+numTest)
  //3.5 Train model and optimize model with validation set
    val numRanks = List(8, 12)
    val numIters = List(10, 20)
    val numLambdas = List(0.1, 10.0)
    var bestRmse = Double.MaxValue
    var bestModel: Option[MatrixFactorizationModel] = None
    var bestRanks = -1
    var bestIters = 0
    var bestLambdas = -1.0
	// 寻找优化参数的模型
    for(rank <- numRanks; iter <- numIters; lambda <- numLambdas){
      val model = ALS.train(trainSet, rank, iter, lambda)
      val validationRmse = computeRmse(model, validationSet)
      println("RMSE(validation) = "+validationRmse+" with ranks="+rank+", iter="+iter+", Lambda="+lambda)
      if (validationRmse < bestRmse) {
        bestModel = Some(model)
        bestRmse = validationRmse
        bestIters = iter
        bestLambdas = lambda
        bestRanks = rank
      }
    }
    //3.6 Evaluate model on test set
	// 用测试集来评估模型
	// 测试集均方根差
    val testRmse = computeRmse(bestModel.get, testSet)
    println("The best model was trained with rank="+bestRanks+", Iter="+bestIters+", Lambda="+bestLambdas+
      " and compute RMSE on test is "+testRmse)
    //3.7 Create a baseline and compare it with best model
	// 创建基线 并与模型进行比较
    val meanRating = trainSet.union(validationSet).map(_.rating).mean() // 训练集与验证集和的均数
	// 最佳根均方错误线(基线)
    val bestlineRmse = new RegressionMetrics(testSet.map(x=>(x.rating, meanRating))).rootMeanSquaredError  // 测试集与均数的均方根差
	// testRmse(这个数应该更优,值更小)
    val improvement = (bestlineRmse - testRmse)/bestlineRmse*100
    println("The best model improves the baseline by "+"%1.2f".format(improvement)+"%.")
    //3.8 Make a personal recommendation
	// 进行个人推荐, 排除自己已经评分内容
    val moviesId = myRatings.map(_.product)
    val candidates = sc.parallelize(movies.keys.filter(!moviesId.contains(_)).toSeq)
    val recommendations = bestModel.get
    .predict(candidates.map(x=>(0, x)))
    .sortBy(-_.rating)
    .take(50)
    var i = 0
    println("Movies recommended for you:")
    recommendations.foreach{ line=>
      println("%2d".format(i)+" :"+movies(line.product))
      i += 1
    }
  sc.stop()
  }
}
导入引用库

三、打包部署
程序运行时,需要指定输入数据路径,数据包含了ratings.dat和movies.dat,数据都包含在了一个数据包。点击下载, 然后解压。
配置运行参数
- 点击edit configuration,在左侧点击该项目。在右侧在右侧VM options中输入“-Dspark.master=local”,指示本程序本地单线程运行 
- 在Program argguemnts指定,上面解压的路径。 
 然后,在IDEA上选择MovieLensALS右键选择运行,即可运行了。
 按照引导,输入自己的评价后,最后输出形式如下:- The best model was trained with rank=12, Iter=20, Lambda=0.1 and compute RMSE on test is 0.868464888081759 
 The best model improves the baseline by 22.01%.
 Movies recommended for you:
 0 :Julien Donkey-Boy (1999)
 1 :Love Serenade (1996)
 2 :Catwalk (1995)
四、HADOOP集群部署
导出jar包设置

选main类对后,点击OK确定, 这个时候配置已经完成了, 我们就可以进行编译 jar文件了, 选择菜单Build->Build Artifacts..., 生成的文件路径为/out/artifacts/MovieLensALS_jar/MovieLensALS.jar
准备HADOOP环境
假设我们的HADOOP环境已经搭建成功。 接下来我们要把需要计算的数据文件上传到hadoop; 首先,在hadoop上面创建文件夹,命令如下:
hdfs dfs -mkdir -p /recommendation/data
上传数据文件命令如下:
hdfs dfs -put *.dat /recommendation/data
这时时候我们可以通过命令查看,上传是否成功
hdfs dfs -cat /recommendation/data/users.dat
运行

在上面红框中,指定了生成的jar文件名, 所在路径, 以及MainClass。这面就是通过spark执行:
/usr/local/spark/spark-2.3.0-bin-hadoop2.7/bin/spark-submit --master local  --class "xyz.pl8.MovieLensALS" /home/hartifacts/movielensals_jar/movielensals.jar /recommendation/data
推荐系统-05-Spark电影推荐、评估与部署的更多相关文章
- SparkMLlib—协同过滤推荐算法,电影推荐系统,物品喜好推荐
		SparkMLlib-协同过滤推荐算法,电影推荐系统,物品喜好推荐 一.协同过滤 1.1 显示vs隐式反馈 1.2 实例介绍 1.2.1 数据说明 评分数据说明(ratings.data) 用户信息( ... 
- 数据算法  --hadoop/spark数据处理技巧    --(9.基于内容的电影推荐  10. 使用马尔科夫模型的智能邮件营销)
		九.基于内容的电影推荐 在基于内容的推荐系统中,我们得到的关于内容的信息越多,算法就会越复杂(设计的变量更多),不过推荐也会更准确,更合理. 本次基于评分,提供一个3阶段的MR解决方案来实现电影推荐. ... 
- 【大数据 Spark】利用电影观看记录数据,进行电影推荐
		利用电影观看记录数据,进行电影推荐. 目录 利用电影观看记录数据,进行电影推荐. 准备 1.任务描述: 2.数据下载 3.部分数据展示 实操 1.设置输入输出路径 2.配置spark 3.读取Rati ... 
- 利用Surprise包进行电影推荐
		Surprise(Simple Python Recommendation System Engine)是一款推荐系统库,是scikit系列中的一个.简单易用,同时支持多种推荐算法(基础算法.协同过滤 ... 
- Spark学习笔记——构建基于Spark的推荐引擎
		推荐模型 推荐模型的种类分为: 1.基于内容的过滤:基于内容的过滤利用物品的内容或是属性信息以及某些相似度定义,来求出与该物品类似的物品. 2.协同过滤:协同过滤是一种借助众包智慧的途径.它利用大量已 ... 
- 利用python实现电影推荐
		"协同过滤"是推荐系统中的常用技术,按照分析维度的不同可实现"基于用户"和"基于产品"的推荐. 以下是利用python实现电影推荐的具体方法 ... 
- 转利用python实现电影推荐
		“协同过滤”是推荐系统中的常用技术,按照分析维度的不同可实现“基于用户”和“基于产品”的推荐. 以下是利用python实现电影推荐的具体方法,其中数据集源于<集体编程智慧>一书,后续的编程 ... 
- 数据挖掘-MovieLens数据集_电影推荐_亲和性分析_Aprioro算法
		#!/usr/bin/env python2 # -*- coding: utf-8 -*- """ Created on Tue Feb 7 14:38:33 201 ... 
- 基于Azure构建PredictionIO和Spark的推荐引擎服务
		基于Azure构建PredictionIO和Spark的推荐引擎服务 1. 在Azure构建Ubuntu 16.04虚拟机 假设前提条件您已有 Azure 帐号,登陆 Azure https://po ... 
- Azure构建PredictionIO和Spark的推荐引擎服务
		Azure构建PredictionIO和Spark的推荐引擎服务 1. 在Azure构建Ubuntu 16.04虚拟机 假设前提条件您已有 Azure 帐号,登陆 Azure https://port ... 
随机推荐
- Beta阶段——第3篇 Scrum 冲刺博客
			Beta阶段--第3篇 Scrum 冲刺博客 标签:软件工程 一.站立式会议照片 二.每个人的工作 (有work item 的ID) 昨日已完成的工作 人员 工作 林羽晴 完成了报表数据的接口函数 顾 ... 
- 1.11 UML 类图(多看多用就熟悉了)(节选自:《大话设计模式》)
			类:用矩形框表示(类图分三层) 第一层显示类的名称:(如果是抽象类,就用斜体显示) 第二层是类的特性,通常就是字段和属性: 第三层是类的操作,通常是方法或行为. (注意前面的符号,“+” 表示 pub ... 
- 使用JQuery 合并两个 json 对象
			一,保存object1和2合并后产生新对象,若2中有与1相同的key,默认2将会覆盖1的值 var object = $.extend({}, object1, object2); 二,将2的值合并到 ... 
- 从零开始学习Vue(四)
			这里引入一个概念SPA(single Page Application), 接着上次的例子,我们在页面底部做了一个Tab的菜单,点击不同的按钮应该是显示不同的内容. 按传统的MVC的思维,我要在Con ... 
- 巧用call,appl有 根据对象某一属性求最大值
			查找对象数组中某属性的最大最小值的快捷方法 例如要查找array数组中对象的value属性的最大值 var array=[ { "index_id": 119, "are ... 
- 移动端常用的 meta设置
			<meta charset="utf-8"> <meta name="viewport" content="width=device ... 
- Vm install centos7
- Java自动装箱中的缓存原理
			今天看到一道'经典'面试题: Integer a = 100; Integer b = 100; System.out.println(a==b); Integer a2 = 200; Integer ... 
- Java的File.separator
			一.File类 在Windows下的路径分隔符(\)和在Linux下的路径分隔符(/)是不一样的,当直接使用绝对路径时,跨平台会报No Such file or diretory异常. File中还有 ... 
- leetCode 典型回溯例子
			39题,翻译题目:给定一组候选集和一个目标值,在c的所有组合中,找出所有总和等于T的组合. 候选数组c中同一个数可以被选择多次(不限次数) 分析: 典型的回溯法应用 对数组里面的每个数,用递归的方式相 ... 
