本文记录了在spark上协同过滤算法的相关内容,如果有做相关工作的同学,可以邮件与我联系 zhaoliang19960421@outlook.com
本文参考了spark协同过滤,在此表示感谢
协同过滤算法的本质是在全局范围内统计用户的行为,对每个行为进行打分记录,找到行为最相似的两人或者所有人的行为最相似的两个物品。具体的协同过滤的过程如下图所示
其中cos距离的计算方式如下图所示
具体的操作方式如下( 以用户的协同过滤为例):
- 在全局范围对,每个用户对每个商品进行打分(对于不同的行为可以给与不同的分值,代表不同的权重)
- 每一个用户用一个向量来表示,向量长度是商品个数,然后对于用户而言两两计算cos距离
- 分母是每个向量的模长, 每个用户的向量模长,依次计算即可
- 在计算cos的分子时,当且仅当两个向量在对应位置上都有值时才有结果
- 那么仅计算每个商品都有打分的商品即可,即对于每个用户而言,以商品为主键进行join,得到两两用户之间都有行为的商品,依次相乘求和后,即可得到cos的分子(做上三角取值,因为用户两两join会出现,AB、BA 两行数据)
- 在获得两两用户之间的cos分子,分别join每个用户的向量模型,做除法得到两个用户之间的cos距离
- 得到的两个用户之间的距离的dataframe保存在hdfs中后续使用
package analysis.theme
import breeze.numerics.{
pow, sqrt}
import conf.DateUtil.getFrontDay
import org.apache.spark.sql.{
DataFrame, SaveMode, SparkSession}
import org.apache.spark.sql.expressions.UserDefinedFunction
import org.apache.spark.sql.functions._
/**
* @author zhaoliang6@xiaomi.com on 20210506
* 基于用户行为的协同过滤算法
*/
object UserItemCF {
def main(args: Array[String]): Unit = {
val spark: SparkSession = new SparkSession.Builder().appName(this.getClass.getSimpleName).getOrCreate()
val Array(startDate: String, endDate: String, savePath: String) = args
val userItemScoreDf = getUserItemScoreDf(spark, startDate, endDate)
val itemCFDf = calcuate(spark, userItemScoreDf, Array("imei", "product_id", "score"), "item")
itemCFDf.write.mode(SaveMode.Overwrite).save(savePath)
val simItemDf = exp_itemCF(spark)
}
/**
* 获得用户-商品-得分 矩阵,其中不同的动作获得得分不同
*/
def Action2ScoreUDF(scoreMap: Map[String, Int]): UserDefinedFunction = udf((action: String) => scoreMap.getOrElse(action, 0))
def getUserItemScoreDf(sparkSession: SparkSession, startDate: String, endDate: String): DataFrame = {
val scoreMap: Map[String