基于Jaccard算法的用户欣赏历史保举商品体系实战+springboot+vue源码实现 ...

打印 上一主题 下一主题

主题 1826|帖子 1826|积分 5478

大家好,这里是小罗毕设工作室。今天给大家带来了一套完整的保举体系: “基于Jaccard算法的用户欣赏历史保举商品体系”。 体系源码后端实现是springboot,前端是vue3。 

视频演示

     基于Jaccard算法的用户欣赏历史保举商品体系实战
  
图片截图




算法原理先容

假设我们有两个商品:商品A和商品B。商品A被用户{小明,小红,小张}欣赏过,商品B被用户{小红,小张,小李}欣赏过。
得到两个用户群体集合 : {小明,小红,小张}    {小红,小张,小李}  。
我们通过Jaccard算法,将两个集合先取交集得到 {小红,小张} ,大小是2 , 在取并集得到 {小明,小红,小张,小李},大小是4。
因此Jaccard相似度=2/4=0.5,这个值表现两个商品的相似程度,值越靠近1表现两个商品越相似(被雷同用户群体欣赏),体系会优先保举相似度高的商品。


实现流程


根本数据预备

起首我们需要预备用户的行为数据表:

  1. CREATE TABLE `user_behaviors` (
  2.   `id` bigint NOT NULL AUTO_INCREMENT COMMENT '行为ID,自增主键',
  3.   `user_id` bigint NOT NULL COMMENT '用户ID',
  4.   `item_id` bigint NOT NULL COMMENT '物品ID',
  5.   `rating` decimal(3,1) DEFAULT NULL COMMENT '评分(1-5分)',
  6.   `behavior_type` varchar(20) NOT NULL COMMENT '行为类型(VIEW-浏览,LIKE-喜欢,PURCHASE-购买)',
  7.   `timestamp` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '行为发生时间',
  8.   PRIMARY KEY (`id`)
  9. ) ENGINE=InnoDB COMMENT='用户行为记录表';
复制代码

之以是这里有评分字段,是因为后续要扩展 基于协同过滤算法的用户评分保举体系
固然这里还要有用户表和商品表:

  1. CREATE TABLE `items` (
  2.   `id` bigint NOT NULL AUTO_INCREMENT COMMENT '物品ID,自增主键',
  3.   `name` varchar(200) NOT NULL COMMENT '物品名称',
  4.   `description` text COMMENT '物品描述',
  5.   `category` varchar(50) DEFAULT NULL COMMENT '物品类别',
  6.   `price` decimal(10,2) DEFAULT NULL COMMENT '物品价格',
  7.   PRIMARY KEY (`id`)
  8. ) ENGINE=InnoDB COMMENT='商品表';
  9. CREATE TABLE `users` (
  10. `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID,自增主键',
  11. `username` varchar(50) NOT NULL COMMENT '用户名',
  12. `email` varchar(100) NOT NULL COMMENT '用户邮箱',
  13. `password` varchar(100) NOT NULL COMMENT '用户密码',
  14. PRIMARY KEY (`id`)
  15. ) ENGINE=InnoDB  COMMENT='用户表';
复制代码


表创建好之后,我们需要写好基本的用户登录,商品列表,商品详情等根本接口,然后保证有丰富的行为数据落库,这样保举体系才能发挥作用。
这些基本的接口我就不讲了,主要讲解一下用户保举接口的实现。

完整体系源码我已经整理清除:

  1. gitcode巅抗目/hadluo2/springboot_vue.git
复制代码
用户保举接口的实现

我将代码的流程整理成了一个流程图,起首我们需要构造一个Map结构数据:


 这些数据就是查询用户行为表,将全部的行为数据,按照商品分类,每一个商品都对应了一个用户群体集合。
然后还是查询用户行为表 , 将当前用户的行为数据查询出来,进行下面流程:


 关键的核心点就是:将当前保举用户买过的商品id对应其他也买过的这个商品的用户作为一个用户集合,然后取全部商品对应的用户群体集合(许多个),然后一个一个经过Jaccard算法盘算相似度,把这个相似度最为评分,最后取出评分高的商品最为保举商品。

讲到这里,你应该能懂了,下面看下关键代码实现:

  1. /**
  2.     完整代码实现:gitcode巅抗目/hadluo2/springboot_vue.git
  3. * 基于用户浏览历史推荐物品
  4. * 主要步骤如下:
  5. * 1. 获取用户最近的浏览记录,按时间倒序排列
  6. * 2. 获取所有用户的浏览记录,构建物品-用户倒排索引
  7. * 3. 计算用户最近浏览物品与其他物品的相似度
  8. * 4. 考虑时间衰减因素,为每个候选物品计算最终得分
  9. * 5. 返回得分最高的N个物品作为推荐结果
  10. * @param userId 用户ID
  11. * @param numRecommendations 推荐数量
  12. * @return 推荐的物品列表
  13. */
  14. public List<Item> recommendBasedOnBrowsingHistory(Long userId, int numRecommendations) {
  15.     // 1. 获取用户最近的浏览记录
  16.     // 创建查询条件:匹配用户ID和浏览行为,按时间戳降序排序
  17.     LambdaQueryWrapper<UserBehavior> wrapper = new LambdaQueryWrapper<>();
  18.     wrapper.eq(UserBehavior::getUserId, userId)
  19.            .eq(UserBehavior::getBehaviorType, "VIEW")
  20.            .orderByDesc(UserBehavior::getTimestamp);
  21.     List<UserBehavior> userViews = userBehaviorRepository.selectList(wrapper);
  22.    
  23.     // 如果用户没有浏览记录,返回空列表
  24.     if (CollectionUtils.isEmpty(userViews)) {
  25.         return Collections.emptyList();
  26.     }
  27.     // 2. 获取所有用户的浏览记录
  28.     // 查询所有用户的浏览行为,用于后续计算物品相似度
  29.     List<UserBehavior> allViews = userBehaviorRepository.selectList(
  30.         new LambdaQueryWrapper<UserBehavior>()
  31.             .eq(UserBehavior::getBehaviorType, "VIEW")
  32.     );
  33.     // 3. 构建物品-用户的倒排索引
  34.     // key: 物品ID, value: 浏览过该物品的用户ID集合
  35.     Map<Long, Set<Long>> itemUserMap = new HashMap<>();
  36.     for (UserBehavior view : allViews) {
  37.         // computeIfAbsent: 如果key不存在,则创建一个新的HashSet
  38.         itemUserMap.computeIfAbsent(view.getItemId(), k -> new HashSet<>())
  39.                    .add(view.getUserId());
  40.     }
  41.     // 4. 计算物品相似度和推荐得分
  42.     // 存储每个候选物品的最终得分
  43.     Map<Long, Double> itemScores = new HashMap<>();
  44.     // 获取用户已浏览过的物品ID集合,用于排除推荐
  45.     Set<Long> userViewedItemIds = userViews.stream()
  46.         .map(UserBehavior::getItemId)
  47.         .collect(Collectors.toSet());
  48.     // 遍历用户的每个浏览记录
  49.     for (UserBehavior userView : userViews) {
  50.         // 获取 浏览该物品的 所有用户
  51.         Set<Long> itemUsers = itemUserMap.get(userView.getItemId());
  52.         if (itemUsers == null) continue;
  53.         // 遍历所有物品,计算与当前浏览物品的相似度
  54.         for (Map.Entry<Long, Set<Long>> entry : itemUserMap.entrySet()) {
  55.             Long otherItemId = entry.getKey();
  56.             // 该用户浏览过了这个商品id, 直接排除
  57.             if (userViewedItemIds.contains(otherItemId)) continue;
  58.             // 浏览过这个商品的 其他用户
  59.             Set<Long> otherItemUsers = entry.getValue();
  60.             // 使用Jaccard相似度计算物品相似度
  61.             // Jaccard相似度 = 两个集合的交集大小 / 并集大小
  62.             //完整代码请见:gitcode巅抗目/hadluo2/springboot_vue.git
  63.             double similarity = calculateJaccardSimilarity(itemUsers, otherItemUsers);
  64.             
  65.             // 考虑时间衰减因素   相当于一个优化因子
  66.             // 浏览时间越近,权重越大(1/1, 1/2, 1/3, ...)
  67.             //完整代码请见:gitcode巅抗目/hadluo2/springboot_vue.git
  68.             // 累加相似度得分(考虑时间权重)
  69.             itemScores.merge(otherItemId, similarity * timeWeight, Double::sum);
  70.         }
  71.     }
  72.     // 5. 生成推荐结果
  73.     // 对候选物品按得分降序排序,选择前N个
  74.     return itemScores.entrySet().stream()
  75.         .sorted(Map.Entry.<Long, Double>comparingByValue().reversed())
  76.         .limit(numRecommendations)
  77.         .map(e -> itemRepository.selectById(e.getKey()))
  78.         .filter(Objects::nonNull)
  79.         .collect(Collectors.toList());
  80. }
复制代码

 代码只贴了部分,原理已经教给大家。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

瑞星

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表