传统推荐算法库使用--mahout初体验

news/2024/5/19 21:35:35 标签: 推荐算法, 算法, 机器学习

文章目录

  • 前言
  • 环境准备
  • 调用
  • 混合
  • 总结

前言

郑重声明:本博文做法仅限毕设糊弄老师使用,不建议生产环境使用!!!
老项目缝缝补补又是三年,本来是打算直接重写写个社区然后给毕设使用的。但是怎么说呢,毕竟毕设的主角不是xx社区,这个社区是为我的编译器服务的,为了推广这个编译器,然后我才做了这个社区。然而不幸的是,开题答辩的时候,各位“专家”叫我以xx社区为主,听起来高级。于是没有办法,我只能强行做个社区,怎么做呢,照着以前写的社区抄,换个主题呗。但是重新写的成本太高了(一开始我是嫌弃白洞这个项目的部署成本比较高,因为里面确实集成了很多模块,有AI模块有传统微服务模块,当然开源的版本是没有这些东西的,毕竟还是要留点底裤的),但是重写实在难受,找了一圈想要找个开源的,结果都没有找到满意的,没办法,只能把白洞项目拿出来,然后做减法,加一个推荐系统。

推荐系统本来也是打算直接基于Java重写手写一个的,直接写个基于协同滤波的传统算法>推荐算法。但是感谢开源,发现了个牛逼的框架mahout。这不就齐活了,我们直接糊弄糊弄毕设过去了就行了。借用某位大哥的话:你要搞清楚你的目的是什么,没有效益的事情少干。于是鄙人放弃了手写推荐系统,放弃了对netty重新封装。咱们有技术积累,但是没有能够产生实际效益的项目,所以不干,糊弄老师得了。

环境准备

这里的话,因为是糊弄毕设,所以我们是直接冷启动。用的是ItemCF,直接推荐博客。然后呢从100个用户里面数据里面推荐就行了,然后结果缓存起来,一天一推。多了没有,反正我用了这个玩意儿,现场查代码也没事,况且数据量根本就不够。

<!--        mahout推荐系统-->
        <dependency>
            <groupId>org.apache.mahout</groupId>
            <artifactId>mahout-mr</artifactId>
            <version>0.12.2</version>
        </dependency>

导入依赖先。

创建记录表:

CREATE TABLE `user_article_operation` (
	`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
	`create_time` DATETIME NOT NULL COMMENT '操作时间,我们默认抓取比较新的数据来进行统计',
	`userid` BIGINT(20) NULL DEFAULT NULL,
	`article_id` BIGINT(20) NULL DEFAULT NULL,
	`operation` INT(11) NULL DEFAULT NULL COMMENT '0-点赞,1-收藏,2-fork(不同的类型,不同的评分)',
	PRIMARY KEY (`id`) USING BTREE,
	INDEX `key` (`userid`, `article_id`, `operation`) USING BTREE
)
COMMENT='用户对文章的操作表'
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
;

这里的话,我使用的是mybatis-plus创建对应的dao和mapper(这里会使用到比较复杂的sql,得手写)


@Data
@TableName("user_article_operation")
public class BlogRe {

    @TableId(value = "id",type = IdType.AUTO)
    private Long id;

    private Long userid;

    private Long articleId;

    private Integer operation;

    private Date createTime;

    @TableField(exist = false)
    private Integer value;

}

对应的xml文件是:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">


    <mapper namespace="com.huterox.whitehole.whiteholeblog.dao.BlogReDao">

    <!--sql-->
    <select id="getAllUserPreference" resultType="com.huterox.whitehole.whiteholeblog.entity.surface.blogRe.BlogRe">
        SELECT
            userid,
            article_id,
            SUM(
                    CASE operation_type
                        WHEN 0 THEN 2
                        WHEN 1 THEN 3
                        WHEN 2 THEN 5
                        else 0 END
                ) AS "value"
        FROM
            user_article_operation
        GROUP BY user_id,article_id
        limit 100
    </select>
    </mapper>

调用

基本的环境准备好了,我们就得调用了。
这里的我的逻辑是,当用户登录了有数据,那么我就直接推荐,如果没有那就继续走默认,也就是按照热度进行推荐。
在我的项目里面最终是定位到了这里:
在这里插入图片描述
具体的推荐逻辑是这里:
在这里插入图片描述
所以我们在这里重点关注这里的实现就可以:

@Service
public class BlogReServiceImpl implements BlogReService {
    
    @Autowired
    BlogReDao blogReDao;

    @Autowired
    BlogReUserIdDao blogReUserIdDao;
    
    @Override
    public List<Long> recommend(String userId) throws TasteException {
        //注意这里我们限制了100个,我们从100个数据里面去拿到,然后做推荐
        List<BlogRe> userList = blogReDao.getAllUserPreference();
        //创建数据模型
        DataModel dataModel = this.createDataModel(userList);
        //获取用户相似程度
        UserSimilarity similarity = new UncenteredCosineSimilarity(dataModel);
        //获取用户邻居
        UserNeighborhood userNeighborhood = new NearestNUserNeighborhood(2, similarity, dataModel);
        //构建推荐器
        Recommender recommender = new GenericUserBasedRecommender(dataModel, userNeighborhood, similarity);
        //推荐2个
        BlogReUserId userMap = blogReUserIdDao.selectOne(new QueryWrapper<BlogReUserId>().eq("userid", userId));
        List<RecommendedItem> recommendedItems = recommender.recommend(userMap.getId(), 2);
        List<Long> itemIds = recommendedItems.stream().map(RecommendedItem::getItemID).collect(Collectors.toList());
        return itemIds;
    }

    private DataModel createDataModel(List<BlogRe> userArticleOperations) {
        FastByIDMap<PreferenceArray> fastByIdMap = new FastByIDMap<>();
        Map<Long, List<BlogRe>> map = userArticleOperations.stream().collect(Collectors.groupingBy(BlogRe::getUserid));
        Collection<List<BlogRe>> list = map.values();
        for (List<BlogRe> userPreferences : list) {
            GenericPreference[] array = new GenericPreference[userPreferences.size()];
            for (int i = 0; i < userPreferences.size(); i++) {
                BlogRe userPreference = userPreferences.get(i);
                GenericPreference item = new GenericPreference(userPreference.getUserid(), userPreference.getArticleId(), userPreference.getValue());
                array[i] = item;
            }
            fastByIdMap.put(array[0].getUserID(), new GenericUserPreferenceArray(Arrays.asList(array)));
        }
        return new GenericDataModel(fastByIdMap);
    }

}

这里写得很清楚了,当然具体的算法原理也不难,可以去翻翻我往期的博文。有Python手撸的版本。加上几个数据源设配器也能直接用了。核心算法原理很简单,不会就问GPT,只要数学没啥问题就懂,不懂,那就直接调用API也挺好。

这里注意的是:
这里要求用户ID是Long类型。
在这里插入图片描述
所以如果你和我的项目一样用户ID用的不是雪花这种算法,而是UUID,那么你得搞个中间的转换表。我这里没辙,所以只能强行加一个转换表:
在这里插入图片描述
当然我们这里还得记录操作。

        //记录一下操作
        BlogReUserId userMap = blogReUserIdDao.selectOne(new QueryWrapper<BlogReUserId>().eq("userid", userid));
        if(userMap==null){
            BlogReUserId blogReUserId = new BlogReUserId();
            blogReUserId.setUserid(userid);
            blogReUserIdDao.insert(blogReUserId);
        }
        BlogRe blogRe = new BlogRe();
        assert userMap != null;
        blogRe.setUserid(userMap.getId());
        blogRe.setArticleId(blogid);
        blogRe.setCreateTime(new Date());
        blogRe.setOperation(0);
        blogReDao.insert(blogRe);

这里看实际情况,反正我这就先这样操作了。

混合

之后的话就是做混合了
在我这里是直接这样了:

    @Override
    public PageUtils queryPageWithRem(Map<String, Object> params) throws Exception {

        //这里是携带推荐系统的
        PageUtils pageUtils = this.queryPage(params);
        if(params.get("rem").equals("1")){
            //触发满足使用推荐系统条件使用推荐系统
            if (params.get("userid")!=null){
                List<Long> blogIds = blogReService.recommend((String) params.get("userid"));
                List<BlogEntity> blogEntityList = this.list(new QueryWrapper<BlogEntity>().in("blogid", blogIds));
                //这个是按照热度推荐的
                List<BlogEntity> list = (List<BlogEntity>) pageUtils.getList();
                //将两者混合
                list.addAll(blogEntityList);
                pageUtils.setPageSize(list.size());
                pageUtils.setTotalCount(list.size());
            }
        }
        return pageUtils;
    }

数据不够的话可能推荐的数据是空的,所以得混合。之后缓存的话,是我直接在这个项目当中使用了SpringCache。当然最近搞项目的时候,我自己直接基于SpringAop写了个缓存注解实现,项目要求比较灵活,直接手写一个快。

总结

新年快乐~


http://www.niftyadmin.cn/n/5375860.html

相关文章

常见范数介绍

一、在线性代数中&#xff0c;符号 ( ||x|| ) 表示向量 ( x ) 的范数&#xff08;Norm&#xff09;。范数是一个将向量映射到非负值的函数&#xff0c;它衡量了向量的大小或长度。范数可以是多种类型&#xff0c;其中最常见的有&#xff1a; 欧几里得范数&#xff08;L2范数&am…

C++ //练习 6.23 参考本节介绍的几个print函数,根据理解编写你自己的版本。依次调用每个函数使其输入下面定义的i和j

C Primer&#xff08;第5版&#xff09; 练习 6.23 练习 6.23 参考本节介绍的几个print函数&#xff0c;根据理解编写你自己的版本。依次调用每个函数使其输入下面定义的i和j&#xff1a; int i 0, j[2] {0, 1};环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff…

漫画sql数据分析

第一章 数据分析概况 1.1数据分析定义 数据分析是指根据分析目的&#xff0c;用适当的分析方法及工具&#xff0c;对数据进行处理分析&#xff0c;提取有价值的信息&#xff0c;形成有效结论的过程。 1.2数据分析作用 数据分析在我们日常工作中主要有三大作用&#xff0c;…

C语言—字符数组(3)

可能不是那么的完整&#xff0c;先凑合看吧&#xff0c;如果我学会如何修改以后&#xff0c;我慢慢回来修改的 1.编写程序实现对两个字符串的连接功能&#xff1b; 法一:不使用strcat函数,写程序直接实现&#xff0c;记得添加结束符&#xff0c;不然程序访问数组时候将变得不…

MySQL数据库⑨_事务(四个属性+回滚提交+隔离级别+MVCC)

目录 1. 事务的概念和四个属性 2. 事务的支持版本 3. 事务的提交方式 4. 事务的相关演示 4.1 常规操作_回滚_提交 4.2 原子性_演示 4.3 持久性_演示 4.4 begin自动更改提交方式 4.5 单条SQL与事务的关系 5. 事务的隔离级别 5.1 四种隔离级别 5.2 查看与设置隔离级别…

vue3 + Babylon.js 实现3D场景

<script setup>import { ref, getCurrentInstance, onMounted, beforeUnmount } from vueimport * as BABYLON from babylonjs/core/Legacy/legacy // 全部引入import babylonjs/loaders // 模型加载loaderimport * as GUI from babylonjs/gui/2D // 交互组件const { pro…

MyBatis中的XML实现和动态SQL实现

文章目录 一、XML实现1.1增1.2删1.3查1.4改 二、XML方式实现动态SQL2.1if标签2.2trim标签2.3where标签2.4set标签2.5foreach标签2.6include标签和sql标签 一、XML实现 先在新建的XML文件中写入如下内容&#xff1a; <?xml version"1.0" encoding"UTF-8&qu…

【机器学习】数据清洗之处理异常点

&#x1f388;个人主页&#xff1a;甜美的江 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步…