spark实现swing算法 -附Scala代码

本文记录了在工作中使用swing算法实现i2i的相关代码内容,如果做相关工作可以邮件和我联系 liangz1996@hotmail.com
itemcf相关内容参考之前spark实现itemcf-附scala代码

package *

import org.apache.spark.broadcast.Broadcast
import org.apache.spark.rdd.RDD
import org.apache.spark.sql._
import org.apache.spark.sql.expressions.UserDefinedFunction
import org.apache.spark.sql.functions._

import scala.math.{
   pow, sqrt}
import scala.util.Random


object CollaborativeFilteringUtils extends Serializable {
   

    /**
     * 基于item之间的相似度,得到最相似的前N个结果
     *
     * @param orgDf       item1 item2 similarity
     * @param sign        排序方式,默认是1,即采用cos距离按照相似度越大越相似,如果采用欧式距离等越小越相似则该值为-1
     * @param topN        每个item取最相似的前topN个
     * @param minSimScore 最小的相似度分数,默认不做过滤
     * @param whiteSet    i2i右边的i可推荐的内容,如果为null,则全部可推荐
     * @param blackSet    i2i右边的i不可以推荐的内容,如果为null,则全部可推荐
     * @return 当前的id,和最相似的前topN个结果与对应的相似度
     */
    def getI2IMap(orgDf: DataFrame,
                  sign: Int = 1,
                  topN: Int = 100,
                  minSimScore: Double = -10000D,
                  whiteSet: Broadcast[Set[String]] = null,
                  blackSet: Broadcast[Set[String]] = null): RDD[(String, Map[String, Double])] = {
   
        orgDf
            .rdd
            .flatMap(r => Array(
                (r.getString(0), (r.getString(1), sign * r.getDouble(2))), // AB BA 都需要计算相似度
                (r.getString(1), (r.getString(0), sign * r.getDouble(2)))
            ))
            .filter(row => row._2._2 >= minSimScore)
            .filter(row => {
   
                var flag = true
                if (whiteSet != null)
                    flag = whiteSet.value.contains(row._2._1)
                flag
            })
            .filter(row => {
   
                var flag = true
                if (blackSet != null)
                    flag = !blackSet.value.contains(row._2._1)
                flag
            })
            .distinct()
            .groupByKey()
            .map(row => {
   
                val id = row._1
                val map = row._2.toArray.sortBy(_._2).reverse.slice(0, topN).toMap
                (id, map)
            })
    }


    /**
     * 对当前的i2i相似度计算进行评估
     *
     * @param input   计算i2i的原始日志输入,为了方便计算,需要将列名统一成user、item、score
     * @param output  i2i的输出结果,为item1、item2、sim,为防止AB BA只计算一遍的情况,所以在这里需要拆开
     * @param i2iType 当前i2i计算方式
     */
    def metrics(sparkSession: SparkSession,
                input: DataFrame,
                output: DataFrame,
                i2iType: String): Unit = {
   
        println(s"当前i2i的计算方式是${
     i2iType}")
        import sparkSession.implicits._
        println(s"当前日志中共有${
     input.selectExpr("user").distinct().count()}个user")
        println(s"当前日志中共有${
     input.selectExpr("item").distinct().count()}个item")
        val temp1 = output
            .rdd
            .flatMap(row => Array(
                (row.getString(0), row.getString(1), row.getDouble(2)),
                (row.getString(1), row.getString(0), row.getDouble(2))
            ))
            .toDF("item1", "item2", "sim")
        println(s"有${
     temp1.selectExpr("item1").distinct().count()}个item可以进行i2i召回")
        val temp2 = temp1.groupBy("item1").agg(countDistinct("item2").as("count"), min("sim").as("minSim"), max("sim").as("maxSim"))
        val maxMinItem2: Array[(Long, Long)] = temp2.agg(max("count"), min("count"))
            .collect()
            .map(row => (row.
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值