Sparrow RecSys 源码阅读

https://github.com/wzhe06/SparrowRecSys

根据接口进行调试

RecommendationService

在主函数中,RecommendationService是和getrecommendation接口绑定的

context.addServlet(new ServletHolder(new RecommendationService()), "/getrecommendation");

com.sparrowrecsys.online.service.RecommendationService#doGet打一个断点

在这里插入图片描述

找到webroot/index.html, 最后的js

在这里插入图片描述

看js代码:webroot/js/recsys.js

在这里插入图片描述
先找genre为Action的电影,size=8

知道了调用源头在哪之后,看Java里面调用了些什么。

com.sparrowrecsys.online.datamanager.DataManager#getMoviesByGenre

从倒排索引中,根据体裁genre找出电影的ID

List<Movie> movies = new ArrayList<>(this.genreReverseIndexMap.get(genre));

MovieService

任意点击一部电影,进入这个断点:

com.sparrowrecsys.online.service.MovieService#doGet

在主函数中,MovieService是和getmovie接口绑定的

context.addServlet(new ServletHolder(new MovieService()), "/getmovie");

前端的请求来源我估计是webroot/js/recsys.js:182addMovieDetails函数


SimilarMovieService

在主函数中,SimilarMovieService是和getsimilarmovie接口绑定的

context.addServlet(new ServletHolder(new MovieService()), "/getmovie");

调用的是online.recprocess.SimilarMovieProcess类的getRecList的静态方法

具体过程其实分为召回和排序,体现在两个方法中

List<Movie> candidates = candidateGenerator(movie);
List<Movie> rankedList = ranker(movie, candidates, model);

原生的candidateGenerator就是根据体裁做了个单路召回,排序用的是Embedding相似度。embMovie类的一个属性,是加载到内存中的!!!!

RecForYouService

上一个的参数是电影ID,这个的参数是用户ID,是要协同过滤?

从业务上,可以理解为以这个ID登录的用户在主页上看到的信息流?

online.recprocess.RecForYouProcess#getRecList

物料的emb是用graph Embedding算的,用户的emb是用他喜好的物料取平均算的

正常操作应该从redis里面拿特征,而不是一把梭全放内存里面

candidates是800个根据评分(rating)得到的电影,排名第一的是4.3分的辛德勒名单

online.recprocess.RecForYouProcess#ranker

本质上就是个双塔召回


虽然看起来这个代码写得就那么回事,但仔细想想,协同过滤 → \rightarrow 矩阵分解 → \rightarrow emb,好像也有点道理

Spark离线计算的Scala代码

Scala的语法糖实在太甜了,我已经晕了,受不了

Embedding

processItemSequence

单机伪分布式

val conf = new SparkConf()
  .setMaster("local")
  .setAppName("ctrModel")
  .set("spark.submit.deployMode", "client")

处理出item2vec所需的样本序列:

val samples = processItemSequence(spark, rawSampleDataPath)

ratingSamples是评分与时间戳数据

在这里插入图片描述

定义排序UDF

val sortUdf: UserDefinedFunction = udf((rows: Seq[Row]) => {
   
  rows.map {
    case Row(movieId: String, timestamp: String) => (movieId, timestamp) }
    .sortBy {
    case (_, timestamp) => timestamp }
    .map {
    case (movieId, _) => movieId }
})

感觉搞不定了。。需要交互式编程才能理清楚

scala> ratingSamples
res6: org.apache.spark.sql.DataFrame = [userId: string, movieId: string ... 2 more fields]

scala> ratingSamples.where(col("rating") >= 3.5).groupBy("userId")
res7: org.apache.spark.sql.RelationalGroupedDataset = RelationalGroupedDataset: [grouping expressions: [userId: string], value: [userId: string, movieId: string ... 2 more fields], type: GroupBy]

scala> var tmp = ratingSamples.where(col("rating") <
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值