• 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())
      }

  • 相关阅读:
    让网络编程更轻松和有趣 t-io
    设计一个百万级的消息推送系统
    前端安全系列之二:如何防止CSRF攻击
    Maven仓库下载jar包失败的处理方案
    SpringBoot2中配置文件的调整,升级SpringBoot2时候注意的坑
    Table折叠小技巧html-demo
    mysql如何分类统计数量
    前台登录和Token信息交互流程
    windows下安装mysql5.6
    【读书笔记】-- 你不知道的JavaScript
  • 原文地址:https://www.cnblogs.com/redhat0019/p/11806135.html
Copyright © 2020-2023  润新知