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

黑马点评-Feed流的实现方案,基于推拉结合模式实现笔记推送

Feed流实现方案

我们关注了博主之后,当用户发布了动态后我们应该把这些数据推送给粉丝,关注推送也叫作Feed(投喂)流,通过无限下拉刷新获取新的信息

  • 传统的模式内容检索: 粉丝需要主动通过搜索引擎或者是其他方式去查找想看的内容
  • 新型Feed流的效果: 系统分析用户到底想看什么,然后主动把内容推送给用户, 不需要用户主动去搜索资源节约用户时间

Feed流实现的两种模式

Timeline: 对发布的信息不做内容筛选,简单的按照内容发布时间排序,常用于好友或关注(朋友圈等)

  • 优点:信息全面不会有缺失并且实现也相对简单

  • 缺点:信息噪音较多用户不一定感兴趣并且内容获取效率低

智能排序:利用智能算法屏蔽掉违规的、用户不感兴趣的内容,推送用户感兴趣的信息来吸引用户

  • 优点: 投喂用户感兴趣的信息,用户粘度很高,容易沉迷
  • 缺点: 如果算法不精准可能会起到反作用即给用户推了不想看的内容

个人页面一般就是基于关注的好友来做Feed流,因此采用Timeline方式只需要拿到我们关注用户的发布的内容然后按照时间排序即可

在这里插入图片描述

拉模式也叫读扩散,每个用户都有自己的发件箱和收件箱

  • 优点节约空间:系统只会将用户关注的博主发布的动态放入到用户的收件箱,用户每次从自己的收件箱中读取信息
  • 缺点拉取信息有延迟:只要用户读取数据时就会去他关注的所有人的发件箱中拉取信息,假设该用户关注了海量用户此时就会拉取很多信息对服务器压力巨大

在这里插入图片描述

推模式也叫写扩散,推模式没有发件箱

  • 优点时效快: 系统主动将博主发布的动态推送到其粉丝的收件箱中,这样用户每次读取信息时就不需要临时拉取
  • 缺点: 内存压力大,假设一个大V发了一个动态此时就会写很多份数据发到他的粉丝收件箱中

在这里插入图片描述

推拉结合也叫读写混合,兼具推和拉两种模式的优点,只要大v才有发件箱

在这里插入图片描述

推送笔记ID到粉丝收件箱

需求: 修改新增探店笔记的业务,在保存Blog对象到数据库的同时推送笔记到粉丝的收件箱

  • 实现收件箱功能: 收件箱要求满足可以根据时间戳对数据排序(降序),同时用户查询收件箱数据时也可以根据角标实现分页查询

传统的分页模式: 查询数据时要求数据库中的数据角标必须固定,否则可能会出现数据重复读取的情况

在这里插入图片描述

Feed流的滚动分页: 记录每次查询操作的最后一条数据,下次查询时会从上次读取的最后一条数据之后开始读取数据

  • List集合: 只能按照角标查询所以不支持滚动分页
  • SortedSet集合: 可以按照集合中元素的score值的范围进行查询,我们每次查询的时候可以记录查询到笔记Id的最小时间戳

在这里插入图片描述

第一步: 修改BlogController中保存笔记的方法,当博主发布完探店笔记后还要将发布笔记的Id推送到所有粉丝的收件箱中,score值是当前的时间戳(默认升序)

// 在RedsiConstants类声明一个常量作为用户收件箱的前缀
public static final String FEED_KEY = "feed:";
@Resource
private IFollowService followService;
@Override
public Result saveBlog(Blog blog) {// 获取登录用户UserDTO user = UserHolder.getUser();blog.setUserId(user.getId());// 保存探店博文boolean isSuccess = save(blog);if(!isSuccess){return Result.fail("新增笔记失败");}// 条件构造器LambdaQueryWrapper<Follow> queryWrapper = new LambdaQueryWrapper<>();// 从follow表中查找博主的所有粉丝select * from follow where follow_user_id = user_idqueryWrapper.eq(Follow::getFollowUserId, user.getId());List<Follow> follows = followService.list(queryWrapper);for (Follow follow : follows) {// 获取粉丝IdLong userId = follow.getUserId();// 推送发布笔记的Id到每个粉丝的收件箱(score值是当前时间戳),每个粉丝都有一个自己的收件箱String key = FEED_KEY + userId;stringRedisTemplate.opsForZSet().add(key, blog.getId().toString(), System.currentTimeMillis());}// 返回笔记的idreturn Result.ok(blog.getId());
}

查询推送笔记

需求: 在个人主页的关注栏中查询并展示推送的Blog信息

ZREVRANGEBYSCORE key 最大值范围 最小值范围 WITHSCORES LIMIT offSet(偏移量) 查询到的个数: 获取指定的score范围内的元素并按照降序排序

  • 最小时间戳: 每次分页查询完成之后要记录查询的最小时间戳,将这个最小时间戳作为下一次分页查询的条件
  • 编译量: 设置要从上次查询的最大值后面跳过几个元素,0表示不跳过元素,1表示跳过一个元素,偏移量的值取决于当前集合内有几个元素和上次查询到的最大值相同

在这里插入图片描述

第一步: 业务中不一定只对Blog进行分页查询,可以使用泛型做一个通用的分页查询

@Data
public class ScrollResult {// 封装查询到的数据private List<?> list;// 记录本次查询的最小时间戳,作为下一次查询的最大值(起始值)private Long minTime;// 记录偏移量private Integer offset;
}

第二步: 在BlogController中创建对应的分页查询方法, 具体实现逻辑在BlogServiceImpl中完成

@GetMapping("/of/follow")
// 由于第一次查询的时候没有传递offset参数,可以设置默认值为0
public Result queryBlogOfFollow(@RequestParam("lastId") Long max, @RequestParam(value = "offset",defaultValue = "0") Integer offset){return blogService.queryBlogOfFollow(max,offset);
}
@Override
public Result queryBlogOfFollow(Long max, Integer offset) {//1. 获取当前用户的IdLong userId = UserHolder.getUser().getId();//2. 查询该用户的收件箱获取该用户对应的SortedSet集合中所有的笔记Id及score值看是否有关注的博主发了笔记String key = FEED_KEY + userId;Set<ZSetOperations.TypedTuple<String>> typeTuples = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, 0, max, offset, 2);//3. 非空判断if (typeTuples == null || typeTuples.isEmpty()){return Result.ok(Collections.emptyList());}//4. 获取SortedSet集合中所有的笔记Id及score值,List集合的大小和Set集合一致,可以略微提高效率避免长度重置ArrayList<Long> ids = new ArrayList<>(typeTuples.size());// 保存最小的时间戳long minTime = 0;// 记录最小时间戳的个数即偏移量int os = 1;for (ZSetOperations.TypedTuple<String> typeTuple : typeTuples) {//4.1 获取推送的Blog的IdString id = typeTuple.getValue();ids.add(Long.valueOf(id));//4.2 将笔记对应的score(时间戳)转换为long类型long time = typeTuple.getScore().longValue();if (time == minTime){// 如果当前的时间戳等于最小时间戳则最小时间戳个数+1os++;}else {// 如果当前时间戳不等于最小时间戳,则把当前时间作为最小时间戳同时把最小时间戳的个数重置为1minTime = time;os = 1;}}// 解决MySQL的in语句的自动按照id大小的排序问题,手动指定排序方式为传入的ids集合中的顺序String idsStr = StrUtil.join(",");//5. 根据推送的ids集合查询所有的blogList<Blog> blogs = query().in("id", ids).last("ORDER BY FIELD(id," + idsStr + ")").list()for (Blog blog : blogs) {//5.1 查询发布该blog的用户信息queryBlogUser(blog);//5.2 查询当前用户是否给该blog点过赞isBlogLiked(blog);}//6. 封装结果并返回ScrollResult scrollResult = new ScrollResult();scrollResult.setList(blogs);scrollResult.setOffset(os);scrollResult.setMinTime(minTime);return Result.ok(scrollResult);
}

相关文章:

黑马点评-Feed流的实现方案,基于推拉结合模式实现笔记推送

Feed流实现方案 我们关注了博主之后,当用户发布了动态后我们应该把这些数据推送给粉丝,关注推送也叫作Feed(投喂)流,通过无限下拉刷新获取新的信息 传统的模式内容检索: 粉丝需要主动通过搜索引擎或者是其他方式去查找想看的内容新型Feed流的效果: 系统分析用户到底想看什么,…...

Re53:读论文 How Can We Know What Language Models Know?

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称&#xff1a;How Can We Know What Language Models Know? ArXiv网址&#xff1a;https://arxiv.org/abs/1911.12543 官方GitHub项目&#xff08;prompt之类的都有&#xff09;&#xff1a;https:…...

YARN工作流程详解

图1 图2 图1 -作业提交阶段&#xff1a; 1、client 提交job,向 ResourceManager【RM】 申请job_id; 2、RM 返回 job_id 及资源提交路径 给 client 3、client 把job所需的资源提交 到 3中指定的路径中 4、client 上传完成资源后&#xff0c;向RM 发送执行作业请求&#xff0c;RM…...

力扣373场周赛题解

第一题&#xff1a; 这个题是一个简单题&#xff0c;数据范围也特别小&#xff0c;所以直接使用模拟方式暴力解答。 直接进行行移动的过程&#xff0c;然后检查移动后的结果是否与移动前相同。 代码&#xff1a; ​ public class Solution {// 将指定行循环右移k次pri…...

编程语言发展史:Rust语言的出现和特点

一、Rust语言的出现 Rust语言是一种由Mozilla开发的系统级编程语言&#xff0c;该语言于2010年首次公布&#xff0c;由Graydon Hoare在Mozilla的工作期间开发&#xff0c;最初是为了替代C而设计的。Rust语言的目标是提供一种安全、高效、并发性强的编程语言&#xff0c;同时保…...

Centos Bind安装与排错

1.配置Centos系统静态IP vi/etc/sysconfig/network-scripts/ifcfg-ens33BOOTPROTOstaticIPADDR192.168.1.100NETMASK255.255.255.0GATEWAY192.168.1.1DNS18.8.8.8:wqsudo systemctl restart network.service 2.安装BIND&#xff08;需要服务器连接互联网&#xff0c;如果服务…...

spark中write算子和format算子详解

在spark中&#xff0c;想要往数据库或者某sink路径里面写数据&#xff0c;存到外部存储系统&#xff0c;如文件系统、数据库或数据仓库&#xff0c;经常会用到write算子。 具体来说&#xff0c;write算子通常与DataFrame或Dataset API一起使用&#xff0c;用于将数据写入持久化…...

设计模式—接口隔离原则(ISP)

1.背景 2002 年罗伯特C.马丁给“接口隔离原则”的定义是&#xff1a;客户端不应该被迫依赖于它不使用的方法&#xff08;Clients should not be forced to depend on methods they do not use&#xff09;。该原则还有另外一个定义&#xff1a;一个类对另一个类的依赖应该建立…...

Jenkins用126邮箱发邮件为什么发不出去

1、检查 Jenkins Location中的邮件地址配置与发邮件的地址配置是否一致 Manage Jenkins -》 system 2、检查地址和端口号 3、检查邮箱的登录配置是否正确&#xff08;这个地方的配置方式网上一抓一大把&#xff0c;自己搜一下就好&#xff09; 4、126邮箱发邮件不需要勾选ssl协…...

怎么给数据库某个字段建立一个前缀索引

说明&#xff1a;SQL调优中重要的一个环节是建立索引&#xff0c;其中有一条是字段值过长字段应该建立前缀索引&#xff0c;即根据字段值的前几位建立索引&#xff0c;像数据库中的密码字段、UUID字段。 因为其随机性&#xff0c;其实根据前几位就可以锁定某一条记录了。前缀索…...

C# 图片下载工具类

写在前面 从浏览器的Html文本中获取图片链接并保存到本地&#xff0c;同时对图片的分辨率和品质进行处理&#xff0c;以满足某些平台的规格需求&#xff1b;可以放到多线程中调用以提高下载效率。 代码实现 public class ImageDownloader{private int minImageSize 1024 * 1…...

嵌入式硬件电路·电平

目录 1. 电平的概念 1.1 高电平 1.2 低电平 2. 电平的使用场景 2.1 高电平使能 2.2 低电平使能 2.3 失能 1. 电平的概念 电平是指电信号电压的大小或高低状态。在数字电子学中&#xff0c;电平有两种状态&#xff0c;高电平和低电平&#xff0c;用来表示二进制中…...

Python文件路径常用操作

1 文件路径 在进行数据处理时&#xff0c;经常要用代码去读文件里的数据&#xff0c;那么首先就得知道这个文件的文件路径。文件路径简单地说就是文件的存放位置。文件路径分为两块&#xff1a;文件夹路径和文件名&#xff0c;文件名又分为文件基本名和扩展名。 举例说明&…...

Redis-Redis 高并发分布式锁

集群分布式场景高并发 1.negix配置代理和路由 高并发场景超卖问题 1.使用原生redis控制超卖时(若是商品&#xff0c;则可以将商品id作为锁对象)&#xff0c;会遇到的问题 问题一&#xff1a;若直接使用&#xff1a;将获取锁的对象和设置的超时的时间分开&#xff0c;则不能控…...

【推荐系统】MMOE笔记 20231126

paper阅读 任务差异带来的固有冲突实际上会损害至少某些任务的预测&#xff0c;特别是当模型参数在所有任务之间广泛共享时。&#xff08;在说ESMM&#xff09; 共享底层参数可以减少过拟合风险&#xff0c;但是会遇到任务差异引起的优化冲突&#xff0c;因为所有任务都需要在…...

4. 标准 IO 库

4. 标准 IO 库 1. 标准 IO 简介2. FILE 指针3. 标准输入、标准输出和标准错误4. fopen() 和 flose()5. fread() 和 fwrite()6. fseek 定位7. 检查或复位状态7.1 feof()7.2 ferrof()7.3 clearerr() 8. 格式化 IO8.1 格式化输出8. 2 格式化输入 9. IO 缓冲9.1 文件 IO 的内核缓冲…...

SAP Smartform小结

SAP系统做打印单据用的, 感觉很不好用, 特别是要嵌入韩文时必须使用嵌入的word编辑器,运行速度简直不可忍受. 见过一些Adobe interactive form的示例, 看着相当不错, 不过据说需要花money额外买licence, 哪有smartform这种免费东西来得实惠. 一般打印需求,会要求有标题抬头,打…...

KVM虚拟机的NAT网络模式原理及过程展示

NAT的方式及原理 NAT方式是KVM安装后的默认方式。 它支持主机与虚拟机的互访&#xff0c;同时也支持虚拟机访问互联网&#xff0c;但不支持外界访问虚拟机。 default是宿主机安装虚拟机支持模块的时候自动安装的。 其中 virbr0是由宿主机虚拟机支持模块安装时产生的虚拟网络接…...

亚马逊云科技向量数据库助力生成式AI成功落地实践探秘(一) ​

随着大语言模型效果明显提升&#xff0c;其相关的应用不断涌现呈现出越来越火爆的趋势。其中一种比较被广泛关注的技术路线是大语言模型&#xff08;LLM&#xff09;知识召回&#xff08;Knowledge Retrieval&#xff09;的方式&#xff0c;在私域知识问答方面可以很好的弥补通…...

C# MemoryCache的使用和封装

封装个缓存类&#xff0c;方便下次使用。 using Microsoft.Extensions.Caching.Memory; using System; using System.Collections.Generic;namespace Order.Core.API.Cache {public class GlobalCache C#有偿Q群&#xff1a;927860652{private static readonly MemoryCache …...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...