Spark使用word2vec训练item2vec实现内容相关推荐

之前使用spark als训练协同过滤,然后导出itemvectors做相似度计算,后来学到了可以用word2vec实现item2vec的训练效果貌似更好,试了一下果然不错;

spark版本:2.3.1,开发语言为JAVA

几大步骤

读取查看、点击、播放等行为数据,我用的是播放数据;

数据整理成(userid, itemid, playcnt)的形式,这个数据可能是聚合N天得到的;

过滤掉playcnt为小于3的数据,我把这些过滤掉,觉得这个数据没有贡献;

按照userid聚合,得到(userid, list(itemid))的形式;

训练word2vec;

导出model.vectors(),里面包括word和对应的向量vector,其中word其实就是itemid

crossjoin计算两两相似度,取相似度TOP N;

将结果存入mysql,后续可以加载到REDIS实现实时相似推荐;

代码实现

读取播放数据:

Dataset<Row> playDatas = spark.sql(

        "select user_id, item_id, play_cnt " +

                "from hive_play_table group by user_id, item_id");


做数据按userid聚合:

playDatas = playDatas

        // 删除掉只播放3次以下的数据

        .filter("play_cnt>2")

        // 按userid聚合

        .groupBy("user_id")

        .agg(collect_list("item_id").as("item_ids"))

        // 至少操作过2个元素

        .where(size(col("item_ids")).geq(2));


训练word2vec:

Word2Vec word2Vec = new Word2Vec()

        .setInputCol("item_ids")

        .setOutputCol("word2vec_result")

        .setVectorSize(50)

        .setMinCount(0)

        .setMaxIter(50)

        .setSeed(123);

Word2VecModel word2VecModel = word2Vec.fit(playDatas);


实现df的cross join:

Dataset<Row> vectorsA = word2VecModel

        .getVectors()

        .select(

                col("word").as("itemIdA"),

                col("vector").as("vectorA"));

Dataset<Row> vectorsB = word2VecModel

        .getVectors()

        .select(

                col("word").as("itemIdB"),

                col("vector").as("vectorB"));

// self cross join

Dataset<Row> crossDatas = vectorsA.crossJoin(vectorsB);


注册余弦相似度计算函数:

spark.udf().register(

        "vectorCosinSim",

        new UDF2<Vector, Vector, Double>() {

            @Override

            public Double call(Vector vectora, Vector vectorb) throws Exception {

                return SimilarityUtils.cosineSimilarity(vectora, vectorb);

            }

        },

        DataTypes.DoubleType

);


其中调用的余弦相似度计算函数,使用JAVA实现:

public static double cosineSimilarity(Vector featuresLeft, Vector featuresRight) {

    double[] dataLeft = featuresLeft.toArray();

    List<Float> lista = new ArrayList<>();

    if (dataLeft.length > 0) {

        for (double d : dataLeft) {

            lista.add((float) d);

        }

    }

    double[] dataRight = featuresRight.toArray();

    List<Float> listb = new ArrayList<>();

    if (dataRight.length > 0) {

        for (double d : dataRight) {

            listb.add((float) d);

        }

    }

    return cosineSimilarity(lista, listb);

}


实现相似度计算,并过滤掉自身和自身的计算:

crossDatas = crossDatas

        .withColumn(

                "cosineSimilarity", callUDF(

                        "vectorCosinSim", col("vectorA"), col("vectorB")))

        .select("itemIdA", "itemIdB", "cosineSimilarity")

        .filter(col("itemIdA").notEqual(col("itemIdB")));


使用 spark的Window,提取每个group的topn:

// 按照相似度倒序排列取TOP 300

WindowSpec windowSpec = Window.partitionBy("itemIdA").orderBy(col("cosineSimilarity").desc());

crossDatas = crossDatas

        .withColumn("simRank", rank().over(windowSpec))

        .where(col("simRank").leq(200));


将数据聚合成每个Item的推荐列表的形式:

crossDatas = crossDatas

        .groupBy("itemIdA")

        .agg(

                collect_list("cosineSimilarity").as("columnSims"),

                collect_list("itemIdB").as("itemIds")

        ).select(

                col("itemIdA").as("item_id").cast(DataTypes.LongType),

                col("columnSims").as("column_sims").cast(DataTypes.StringType),

                col("itemIds").as("item_ids").cast(DataTypes.StringType)

        );


将数据覆盖写入MySQL:

crossDatas.write().mode(SaveMode.Overwrite).jdbc(

        MysqlConfig.ONLINE_MYSQL_MASTER_URL,

        "item2vec_sims",

        MysqlConfig.getOnlineProperties()

);


在数据库中,我们根据item_id,提取到item_ids,可以用于直接的推荐;其中column_sims也记录了对应的相似度权重,如果需要加权的话也可以直接提取;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容