当前位置: 首页 > ds >正文

Feed流推送之订阅推送

分类

feed流分为TimeLine和智能排序,前者不对内容进行过滤,一般根据发布的时间来进行排序,一般用于好友动态或者推送关注的人的消息,而后者一般有着复杂的算法,可以根据算法智能地向目标用户推送内容,例如抖音的推送算法。

方案

Feed流推送一般有着三种方案

  1. 推模式,即发布者一有新消息,则将消息全部发送到粉丝的收件箱中,优点延迟小,缺点内存占用高
  2. 拉模式,即发布者将新消息发送到自己的发件箱,用户上线后从所有关注的人的列表中拉取新消息,优点占用内存小,缺点是读延迟高。
  3. 推拉结合的混合模式,通过推拉结合,根据发布者或者粉丝的分类进行合适的推拉模式选择,例如大V的粉丝数量庞大,对于他的活跃粉丝,采用推模式,对于普通粉丝,采用拉模式

在黑马点评的feed推送关注的博主的新发布博客中,一般用户的粉丝数不会特别大,采用推模式来实现,基于redis来实现推模式。

方案的实现

数据结构的选择:用户的收件箱应该根据用户关注的博主发布的博客的时间戳来进行排序,而redis中能够进行排序的有两种数据结构,分别为list和SortedSet, list为传统角标排序,而sortedSet能够根据给定的值来排序,这里用sortedset数据结构,根据关注的博主发布的博客的时间戳来实现

思路:

1.获取当前用户

  1. 获取redis中的收件箱,并判空
  2. 解析收件箱中的博客,解析出博客的id和时间戳
  3. 根据id查找博客
  4. 封装返回

粉丝查询代码:

/*** 滚动分页查询关注的人的博客,从时间为max前的第offset条开始查询* @param max * @param offset * @return*/
@Override
public Result queryBlogOfFollow(Long max, Integer offset) {//获取当前用户Long userId = UserHolder.getUser().getId();//获取redis中的收件箱String key = RedisConstants.FEED_KEY+userId;Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, 0, max, offset, 3);if(typedTuples == null || typedTuples.isEmpty()){return Result.ok();}//解析博客List<Long> Ids = new ArrayList<>(typedTuples.size());long timeMin =  0;int count = 1;for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {//获取idString str = typedTuple.getValue();if(str!=null) Ids.add(Long.valueOf(str));//获取时间戳Long time = typedTuple.getScore().longValue();if(Objects.equals(time, timeMin)){count++;}else{count = 1;}timeMin = time;}//解析id,根据id查找博客String idsStr = StrUtil.join(",",Ids);List<Blog> blog = blogService.query().in("id", Ids).last("ORDER BY FIELD(id," + idsStr + ")").list();for (Blog blog1 : blog) {queryBlogUser(blog1);isBlogLiked(blog1);}//封装返回ScrollResult scrollResult = new ScrollResult();scrollResult.setList(blog);scrollResult.setMinTime(timeMin);scrollResult.setOffset(count);return Result.ok(scrollResult);
}

发布者代码:

/*** 保存博客* @param blog* @return*/
@Override
public Result saveBlog(Blog blog) {
// 获取登录用户
UserDTO user = UserHolder.getUser();
blog.setUserId(user.getId());
// 保存探店博文
boolean success = blogService.save(blog);
if(!success){return Result.fail("发布失败");
}
/*
将消息推送到所有粉丝
*/
//获取粉丝
List<Follow> followUser = followService.query().eq("follow_user_id", user.getId()).list();
//推送消息
for(Follow follow:followUser){Long blogId = blog.getId();stringRedisTemplate.opsForZSet().add(RedisConstants.FEED_KEY+follow.getUserId() ,blogId.toString() ,System.currentTimeMillis());
}
// 返回id
return Result.ok(blog.getId());
}
http://www.xdnf.cn/news/5765.html

相关文章:

  • ChromeDriver 技术生态与应用场景深度解析
  • VUE中通过DOM导出PDF
  • UI-TARS: 基于视觉语言模型的多模式代理
  • FLASH闪存(擦除、编译)
  • Golang 空结构体特性与用法
  • 位运算的巧思:以一道简单题看高效算法的设计精髓
  • 可视化图解算法37:序列化二叉树-II
  • MCP与GitHub的集成:开发者的“自动化流水线”革命
  • ThreadLocal 详解
  • 2025年阿里云ACP大数据分析师认证模拟试题(附答案解析)
  • JVM对象分配与程序崩溃排查
  • Git的基本操作
  • Jupyter-AI Pandas-AI本地使用功能优化
  • 识别人脸人名,只是窗口的中文乱码待解决
  • 数据库实验报告 SQL SERVER 2008的基本操作 1
  • 调出事件查看器界面的4种方法
  • 从规划到完善,原型标注图全流程设计
  • 国产化芯片ZCC3790--同步升降压控制器的全新选择, 替代LT3790
  • 接口和抽象类的区别
  • uniapp-商城-54-后台 新增商品1
  • A Survey of Learning from Rewards:从训练到应用的全面剖析
  • 计算机网络|| 路由器和交换机的配置
  • 运用数组和矩阵对数据进行存取和运算——NumPy模块 之四
  • Excel表的导入与导出
  • RAGFlow 初步尝试 (01)
  • 基于HTTP头部字段的SQL注入:SQLi-labs第17-20关
  • OpenCV4.8 开发实战系列专栏之 49 二值图像分析 -轮廓外接矩形
  • 我用Deepseek + 亮数据爬虫神器 1小时做出輿情分析器
  • 一文了解JavaScript对象
  • Kotlin与Ktor构建Android后端API