spark mllib als推荐引擎学习

推荐算法可以分为:UserCF(基于用户的协同过滤)、ItemCF(基于商品的协同过滤)、ModelCF(基于模型的协同过滤),具体介绍见: http://blog.csdn.net/ygrx/article/details/15501679
spark中的协同过滤算法用的是ALS算法,叫做矩阵分解,其实就是补充二维矩阵中缺失的打分,具体见: http://www.dataguru.cn/article-7049-1.html

Spark ALS推荐实例

我们接下去通过代码来描述下利用spark的mllib如何进行商户或者用户的推荐,假设我们的数据如下:
3563904759267333 473136262280108 1
3563904759484437 836075662280961 1
3563904759746579 102136262280378 1
字段1是用户id,第二个字段是商户id,第三个就是打分
[java]  view plain  copy
  1. val conf = new SparkConf()  
  2.   .setAppName("Mid Recommend")  
  3.   .set("spark.executor.extraClassPath""/opt/cloudera/parcels/CDH/lib/hbase/lib/*")  
  4. val sc = new SparkContext(conf)  

这段代码描述了构建SparkContext,同时加入了hbase需要用的jar包,因为我们的数据需要存入hbase

[java]  view plain  copy
  1. val trans = sc.textFile("/xxx/recommend/card_consume_info_sh/card_consume_info_sh")  
  2.   
  3. var count = 0  
  4. val cardMapping = trans.map { line =>  
  5.   val field = line.split("\t")  
  6.   field(0)  
  7. }.distinct(1).map { line =>  
  8.   count += 1  
  9.   (count.toString, line)  
  10. }  
  11.   
  12. count = 0  
  13. val midMapping = trans.map { line =>  
  14.   val field = line.split("\t")  
  15.   field(1)  
  16. }.distinct(1).map { line =>  
  17.   count += 1  
  18.   (line, count.toString)  
  19. }  
  20.   
  21. saveToHbase(midMapping.map(convert), "mid_mapping")  
  22. saveToHbase(cardMapping.map(convert), "card_mapping")  
  23.   
  24. cardMapping.map { line =>  
  25.   line._1 + "\t" + line._2  
  26. }.saveAsTextFile("/<span style="font-family: Arial, Helvetica, sans-serif;">xxx</span><span style="font-family: Arial, Helvetica, sans-serif;">/recommend/mapping/card_mapping")</span>  
  27. midMapping.map { line =>  
  28.   line._1 + "\t" + line._2  
  29. }.saveAsTextFile("/xxx/recommend/mapping/mid_mapping")  
[java]  view plain  copy
  1. val trans = sc.textFile("/xxx/recommend/card_consume_info_sh/card_consume_info_sh")  
  2. val cardMapping = sc.textFile("/xxx/recommend/mapping/card_mapping").map { line =>  
  3.   val field = line.split("\t")  
  4.   (field(1), field(0))  
  5. }  
  6. val midMapping = sc.textFile("/xxx/recommend/mapping/mid_mapping").map { line =>  
  7.   val field = line.split("\t")  
  8.   (field(0), field(1))  
  9. }  
  10.   
  11. // 进行join  
  12. val rs = trans.map { line =>  
  13.   val field = line.split("\t")  
  14.   (field(0), field(1) + "_" + field(2))  
  15. }.join(cardMapping).map { line =>  
  16.   val field = line._2._1.split("_")  
  17.   (field(0), line._1 + "_" + line._2._2 + "_" + field(1))  
  18. }.join(midMapping).map { line =>  
  19.   val field = line._2._1.split("_")  
  20.   field(1) + "\t" + line._2._2 + "\t" + field(2)  
  21. }  
  22.   
  23. rs.saveAsTextFile("/xxx/recommend/card_consume_info_sh/card_consume_info_sh_mapping")  
由于mllib的Rating类的user和product只能是int,而我们的user和product是String类型,所以需要做一个转换,上述代码将原始数据进行了int和String的mapping,最后我们的数据格式为:2418938 4676 1,第一个表示用户id,第二个表示商品id,第三个字段表示打分

[java]  view plain  copy
  1. val trans = sc.textFile("/xxx/recommend/card_consume_info_sh/card_consume_info_sh_mapping")  
  2.   
  3. val ratings = trans.map { line =>  
  4.   val Array(cardMapping, midMapping, rating) = line.split("\t")  
  5.   Rating(cardMapping.toInt, midMapping.toInt, rating.toDouble)  
  6. }.persist  
  7.   
  8. // 使用ALS训练数据建立推荐模型  
  9. val rank = 8  
  10. val numIterations = 10  
  11. val model = ALS.train(ratings, rank, numIterations, 0.01)  
  12.   
  13. // 从rating中获取user以及product数据集  
  14. val usersProducts = ratings.map {  
  15.   case Rating(user, product, rate) => (user, product)  
  16. }  
  17.   
  18. // 使用推荐模型预对用户和商品进行评分,得到预测评分的数据集  
  19. val predictions = model.predict(usersProducts).map {  
  20.   case Rating(user, product, rate) => ((user, product), rate)  
  21. }  
  22.   
  23. // 真实数据和预测数据进行合并  
  24. val ratesAndPredicts = ratings.map {  
  25.   case Rating(user, product, rate) => ((user, product), rate)  
  26. }.join(predictions)  
  27.   
  28. val MSE = ratesAndPredicts.map { case ((user, product), (r1, r2)) =>  
  29.   val err = (r1 - r2)  
  30.   err * err  
  31. }.mean()  
这段代码我们通过ALS进行模型的训练,主要有3个参数,具体见 http://blog.javachen.com/2015/06/01/how-to-implement-collaborative-filtering-using-spark-als.html
这段代码我们只试了3个参数中的一个情况,然后计算MSE值,这个值越小,说明该model越接近正确值,具体模型的评估同样可以见上个博客 http://blog.javachen.com/2015/06/01/how-to-implement-collaborative-filtering-using-spark-als.html
其实我们这里可以用3个参数多维度的数据进行循环训练模型,计算出MSE值最小的那个model就可以了~
[java]  view plain  copy
  1. // 为每个商户进行推荐  
  2. val products = ratings.map(_.product).distinct(10).collect()  
  3.   
  4. val rawData = new mutable.HashMap[String, String]()  
  5. products.foreach(  
  6.   product => {  
  7.     // 依次为商品推荐用户  
  8.     val rs = model.recommendUsers(product, 10)  
  9.     var value = ""  
  10.     var key = 0  
  11.     // 拼接推荐结果  
  12.     rs.foreach(r => {  
  13.       key = r.product  
  14.       value = value + r.user + ":" + r.rating + ","  
  15.     })  
  16.     rawData.put(key.toString, value.substring(0, value.length - 1))  
  17.   }  
  18. )  
  19. // 存进hbase  
  20. val rs = sc.parallelize(rawData.toSeq).map(convert)  
  21. saveToHbase(rs, "mid_recommend")  
这段代码是为每个商户进行离线推荐,不建议数据量很大,要不然撑爆内存,高版本提供了离线全部推荐的api,只是我的版本是CDH5.4.4,Spark还是1.3.0的版本,所以不支持这个api
[java]  view plain  copy
  1. def saveModel(sc: SparkContext, model: MatrixFactorizationModel): Unit = {  
  2.   model.save(sc, "/xxx/recommend/model")  
  3. }  
  4.   
  5. def loadModel(sc: SparkContext): MatrixFactorizationModel = {  
  6.   return MatrixFactorizationModel.load(sc, "/xxx/recommend/model")  
  7. }  
如果我们需要实时推荐,那么就需要将训练好的模型保存下来,然后需要用的时候再load下,然后用recommendUsers进行推荐。

实时推荐引擎的思考

上段最后提到了实时推荐引擎,有如下的思路,仅供参考:
推荐最重要的就是从初始数据中用算法进行打分,这个根据业务的不同设计的方法不同,然后根据打好分的数据进行模型的训练,训练完了保存下来,需要进行推荐的时候再load过来进行实时推荐。
主要流程:原始数据经过ETL处理生成结构化数据然后用算法进行打分,这块耗时比较长,每天可以凌晨进行ETL抽取;然后根据打分好的数据进行模型的训练,这段时间在ETL之后,需要时间也不短;最后保存模型;加载模型进行实时推荐

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值