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

文章目录

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

前言

郑重声明:本博文做法仅限毕设糊弄老师使用,不建议生产环境使用!!!
老项目缝缝补补又是三年,本来是打算直接重写写个社区然后给毕设使用的。但是怎么说呢,毕竟毕设的主角不是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写了个缓存注解实现,项目要求比较灵活,直接手写一个快。

总结

新年快乐~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/384466.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

事理与事件知识图谱

目录 前言1 事件定义与事理逻辑1.1 事件定义1.2 事理逻辑 2 事理知识图谱与传统知识图谱的区别和联系2.1 事理知识图谱与传统知识图谱的区别2.2 事理知识图谱与传统知识图谱的联系 3 事理知识图谱中的关系3.1 顺承关系3.2 因果关系3.3 条件关系3.4 并发关系3.5 上下位关系 4 事…

HP Pavilion Laptop 15-cs3xxx原装出厂Win10.20H1系统

惠普笔记本HP Pavilion - 15-cs3030tx原厂Windows10系统镜像下载 链接&#xff1a;https://pan.baidu.com/s/1LmdJoN7F3BGvt49ovq-eww?pwdzgmt 提取码&#xff1a;zgmt 适用型号&#xff1a; 15-cs3001tx&#xff0c;15-cs3030tx&#xff0c;15-cs3031tx&#xff0c;15-cs…

每日一练:LeeCode-654、最大二叉树【二叉树+DFS+分治】

本文是力扣LeeCode-654、最大二叉树【二叉树DFS分治】 学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐LeeCode。 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其…

最全面的Docker安装部署,配置镜像加速

安装Docker 卸载旧版 首先如果系统中已经存在旧的Docker&#xff0c;则先卸载&#xff1a; yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 配置Docker的yum仓库 首先…

Codeforces Round 924 (Div. 2)B. Equalize(思维+双指针)

文章目录 题面链接题意题解代码 题面 链接 B. Equalize 题意 给一个数组 a a a&#xff0c;然后让你给这个数组加上一个排列&#xff0c;求出现最多的次数 题解 赛时没过不应该。 最开始很容易想到要去重&#xff0c;因为重复的元素对于答案是没有贡献的。 去重后排序。&a…

HTTP 超文本传送协议

1 超文本传送协议 HTTP HTTP 是面向事务的 (transaction-oriented) 应用层协议。 使用 TCP 连接进行可靠的传送。 定义了浏览器与万维网服务器通信的格式和规则。 是万维网上能够可靠地交换文件&#xff08;包括文本、声音、图像等各种多媒体文件&#xff09;的重要基础。 H…

LLM大模型常见问题解答(2)

对大模型基本原理和架构的理解 大型语言模型如GPT&#xff08;Generative Pre-trained Transformer&#xff09;系列是基于自注意力机制的深度学习模型&#xff0c;主要用于处理和生成人类语言。 基本原理 自然语言理解&#xff1a;模型通过对大量文本数据的预训练&#xff…

LLM之RAG实战(二十五)| 使用LlamaIndex和BM25重排序实践

本文&#xff0c;我们将研究高级RAG方法的中的重排序优化方法以及其与普通RAG相比的关键差异。 一、什么是RAG&#xff1f; 检索增强生成&#xff08;RAG&#xff09;是一种复杂的自然语言处理方法&#xff0c;它包括两个不同的步骤&#xff1a;信息检索和生成语言建模。这种方…

【开源】JAVA+Vue.js实现车险自助理赔系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 角色管理模块2.3 车辆档案模块2.4 车辆理赔模块2.5 理赔照片模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 角色表3.2.2 车辆表3.2.3 理赔表3.2.4 理赔照片表 四、系统展示五、核心代码5.1 查询车…

【PyQt】10 QLineEdit

文章目录 前言一、回显模式&#xff08;EchoMode&#xff09;1.1 四种回显模式1.2 代码展示运行结果 二、校验器2.1 代码2.2 运行结果 三、通过掩码限制输入3.1 代码3.2 运行结果 总结 前言 1、QLineEdit 可以输入单行文字 2、回显模式 3、校验器 4、掩码输入 一、回显模式&am…

图片懒加载:从低像素预览到高清加载

老生常谈的问题&#xff0c;图片太多太大的网站&#xff0c;往往由于图片加载过慢而导致页面白屏时间过长。本次年前最后一更&#xff0c;来讲一个加载方法来处理这种情况。 在使用 Next.js 时&#xff0c;发现其支持模糊图片占位符加载的方式&#xff0c;本文就手动实现一个 图…

最近vscode链接Autodl出现的问题

最近vscode链接Autodl出现的问题 一、问题的概述 在使用vscode连接autodl远程服务器的时候&#xff0c;在vscode的右下角出现了&#xff0c;以下的问题提示&#xff1a; 远程主机可能不符合glibc和libstdc VS Code服务器的先决条件 二、问题的原因 vscode版本过高的问题&…

远程git仓库已有仓库,若想本地代码覆盖远程代码,操作如下

1.首先 2.其次 3.然后 4.最后 git push -f origin "master" -f&#xff1a;强制推送&#xff0c;若远程是空项目&#xff0c;可以换成-u

基于Java (spring-boot)的宿舍管理系统

一、项目介绍 基于Java (spring-boot)的宿舍管理系统功能&#xff1a;登录界面、宿舍管理、学生管理、班级管理、宿舍楼管理、维修记录、晚归记录、请假记录、用户管理、角色管理、菜单管理、日志管理、我收到的、退宿审核&#xff0c;等等等 二、作品包含 三、项目技术 后端语…

MATLAB环境下生成对抗网络系列(11种)

为了构建有效的图像深度学习模型&#xff0c;数据增强是一个非常行之有效的方法。图像的数据增强是一套使用有限数据来提高训练数据集质量和规模的数据空间解决方案。广义的图像数据增强算法包括&#xff1a;几何变换、颜色空间增强、核滤波器、混合图像、随机擦除、特征空间增…

人生就是一场大考

感觉人生就是一场大考&#xff0c;最重要的高考&#xff0c;而这个考试要到49岁左右才有得分。如&#xff0c;当初事业的选择&#xff0c;爱情伴侣的选择&#xff0c;出去在外发展的选择……这都决定了你以后人生高考的走向。现在的你过得怎么样&#xff0c;也是你在人生这场高…

Java实现河南软件客服系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统管理人员2.2 业务操作人员 三、系统展示四、核心代码4.1 查询客户4.2 新增客户跟进情况4.3 查询客户历史4.4 新增服务派单4.5 新增客户服务费 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的河…

机器学习系列5-特征组合、简化正则化

1.特征组合 1.1特征组合&#xff1a;编码非线性规律 我们做出如下假设&#xff1a;蓝点代表生病的树。橙色的点代表健康的树。 您可以绘制一条直线将生病的树与健康的树清晰地分开吗&#xff1f;不可以。这是一个非线性问题。您绘制的任何线条都无法很好地预测树的健康状况…

1【算法】——最大子数组问题(maximum subarray)

一.问题描述 假如我们有一个数组&#xff0c;数组中的元素有正数和负数&#xff0c;如何在数组中找到一段连续的子数组&#xff0c;使得子数组各个元素之和最大。 二.问题分析 分治法求解&#xff1a; 初始状态&#xff1a; low0&#xff1b;highA.length-1&#xff1b;mid&am…

GO 的 Web 开发系列(五)—— 使用 Swagger 生成一份好看的接口文档

经过前面的文章&#xff0c;已经完成了 Web 系统基础功能的搭建&#xff0c;也实现了 API 接口、HTML 模板渲染等功能。接下来要做的就是使用 Swagger 工具&#xff0c;为这些 Api 接口生成一份好看的接口文档。 一、写注释 注释是 Swagger 的灵魂&#xff0c;Swagger 是通过…