scala spark 示例代码

1.   导入隐式转换

import spark.implicits._

2. 读取 / 存储 mongodb 数据并转换为对象 df (不 as 转换也是 DataFrame 对象,但一般会习惯转换一下在进行操作)

case class Rating(val uid: Int, val mid: Int, val score: Double, val timestamp: Int)

val ratingsDF = spark.read
      .option("uri", mongoConfig.uri)
      .option("collection", MONGO_RATINGS_COLLECTION)
      .format("com.mongodb.spark.sql")
      .load()
      .as[Rating]
      .toDF()
  count.write
    .option("uri", mongoConfig.uri)
    .option("collection", MONGO_MOVIE_SCORE_COUNT)
    .format("com.mongodb.spark.sql")
    .mode("overwrite")
    .save() 

3. 将 DataFrame 转换为 sql 表进行操作,   如果例如有时间格式化等功能需要加入 sql 语句中,需要 注册一个 UDF 函数 来操作

   //统计以月为单位每个电影的评分数
    val simpleDateFormat = new SimpleDateFormat("yyyyMM")
    //注册一个UDF函数, 用于将timestamp转换成年月形式
    spark.udf.register("changeDate", (x:Int) => simpleDateFormat.format(new Date(x*1000L)).toInt)
    val mouthCountDF = spark.sql("select mid, count(mid) count, changeDate(timestamp) as yearmouth from ratings group by yearmouth,mid order by count desc")

4. 将 2 个 RDD 通过某个字段进行 join

//统计每种电影类别中评分最高的10个电影
val movieWithScore = movieDF.join(avgMoviesDF, Seq("mid", "mid"))

5. 将 list 转化为 RDD

val genres = List("Action", "Adventure", "Animation", "Comedy", "Ccrime", "Documentary", "Drama", "Family", "Fantasy", "Foreign", "History", "Horror", "Music", "Mystery", "Romance", "Science", "Tv", "Thriller", "War", "Western") 
val genresRDD = spark.sparkContext.makeRDD(genres)

6. 过滤 某个 RDD 中包含另一个 RDD 的数据

  genresRDD.cartesian(movieWithScore.rdd)
      .filter{case (genres, row) =>
         row.getAs[String]("genres").contains(genres)
    }

7. 如果一个RDD 格式为    RDD[(String, Iterable[(Integer, Double)])],  这样的格式,需要对 rdd 中的迭代器中的某个字段进行排序, 例如 Double 这个字段, 并且只取前 10 条记录

  .map{case (genres, item) =>
      (GenresRecommendation(genres, item.toList.sortWith(_._2 > _._2).take(10).map(x => Recommendation(x._1, x._2))))
    }

8. 推荐算法  用户相似度推荐算法 (根据用户对各个电影的评分,计算出用户除了评分电影外,还有可能对那些电影感兴趣,包含计算的字段就是 用户,电影,评分)

//1.首先需要做一个 ALS训练模型 model,那么久需要创建一个训练集, 训练集 为 Rating(org.apache.spark.mllib.recommendation.Rating) 对象, 字段为 3个,如下,: x._1, x._2, x._3   
x._1 为 uid 用户id, x._2 为 mid 电影 id, x._3 为评分 这样的三个字段, 所以需要先将 ratingsRDD 转化成这3个字段的rdd,
val trainData = ratingsRDD.map(x => Rating(x._1, x._2, x._3))
//2.设置训练参数
val (rank, iterations, lambda) = (50, 10, 0.01)  

  //3.创建训练 ALS模型,  也就是后面要进行相似度计算的时候要以这个model为原模型进行匹配计算
  val model = ALS.train(trainData, rank, iterations, lambda)

 //4.要使用这个 model 进行计算,还需要有一个格式为 RDD[(Int, Int)] 这样一个待计算的 Rdd,因为 model 模型创建的时候是  uid, mid, score,  所以这个RDD 第一个 Int 应该是uid, 第二个RDD 是 mid

 所以要先获得这样一个 RDD,  首先获得一个 RDD[Int] 格式的 userRDD,  然后获得一个 RDD[Int] 格式的 movieRDD, 再做 笛卡尔积 就可以获得 RDD[(Int, Int)]

  val userMovies = userRDD.cartesian(movieRDD)

  //5.使用 predict 方法计算相似度

 val preRatings = model.predict(userMovies)

 //转换成我们希望的推荐对象矩阵 (计算出的 preRatings 是一个Rating对象, 通过如下字段就能拿到我们想要的数据, 格式为 RDD[(Int, (Int, Double))],也就是 RDD[(uid, (mid, score))]),然后再通过

  需求转换成我们想要的格式活对象
 val userRecommender = preRatings.map(rating => (rating.user, (rating.product, rating.rating)))
  .groupByKey()
  .map {
     case (uid, recs) => UserRecommender(uid, recs.toList.sortWith(_._2 > _._2).take(20).map(x => Recommenderation(x._1, x._2)))
  }.toDF()

  

 9. 电影相似度推荐算法 (电影相似度是 电影矩阵中  uid, mid, score, 用户对很多电影进行过评分,根据用户对电影的喜好计算出那些电影比较相似, 所以还是使用上面的 model 来进行计算)

//1. model.productFeatures 将会获得一个  RDD[(Int, Array[Double])] 的 RDD, 需要将 Array[Double] 转化为 DoubleMatrix
val movieFeatures = model.productFeatures.map {
    case (mid, freatures) =>
      (mid, new DoubleMatrix(freatures))
  }

  //电影相识度矩阵计算
  val movieRecommender = movieFeatures.cartesian(movieFeatures)
    .filter { case (a, b) => a._1 != b._1 }
    .map {
      case (a, b) =>
    val simSocore = this.consinSim(a._2, b._2)
    (a._1, (b._1, simSocore))
    }.filter(_._2._2 > 0.6)
    .groupByKey()
    .map {
      case (mid, recs) => (MovieRecommender(mid, recs.toList.sortWith(_._2 > _._2).map(x => Recommenderation(x._1, x._2))))
    }.toDF()

  def consinSim(movie1: DoubleMatrix, movie2: DoubleMatrix): Double = {
    movie1.dot(movie2) / (movie1.norm2() * movie2.norm2())
  }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-11-06 16:27  林**  阅读(985)  评论(2编辑  收藏  举报