基于Redis的推荐瀑布流

前言:Redis在目前的互联网公司的应用场景非常的丰富,最近公司为了给产品添加社交属性,仿微信的朋友圈做了一个`骨人云`,包括关注和发现两个频道,再加上本次改版之前的产品首页的五个频道页中的四个频道页,都是推荐的瀑布流,我大量使用`Redis`的SortedSet,这里记录一下,希望给在处理类型业务场景的同学提供一个方向,因为全是自己摸索的,不知道大厂是怎么做的,有不对的地方欢迎指正。

SortedSet的简介

说SortedSet,要先说一下Redis的另外一个数据类型Set,类似于Java的Set,Set是一个字符串的集合,不允许重复的成员变量出现在一个Set中。而SortedSet和Sets类型极为相似,它们之间的主要差别是Sorted-Sets中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。然而需要额外指出的是,尽管SortedSet中的成员必须是唯一的,但是分数(score)却是可以重复的。在Sorted-Set中添加、删除或更新一个成员都是非常快速的操作,其时间复杂度为集合中成员数量的对数。由于SortedSet中的成员在集合中的位置是有序的,因此,即便是访问位于集合中部的成员也仍然是非常高效的。事实上,Redis所具有的这一特征在很多其它类型的数据库中是很难实现的,换句话说,在该点上要想达到和Redis同样的高效,在其它数据库中进行建模是非常困难的。

2. 应用场景

目前主流的就是排行榜,因为SortedSet自带的排序功能,很容易根据按照根据score从小到大或者从大到小的取出一定数量的数据,还可以根据score的值取值在当前的值范围内的数据。比如我们做全站资源的浏览的排行,我们就可以以资源的ID作为member成员,当资源被浏览一次后使用ZINCRBY给对应资源的score加1,这样我们就可以随时的查询当前时刻排行较前的数据

3. 推荐瀑布,下面详细列出我的实现步骤

原理:后端接口返回的时候会返回前端返回数据的中的最大的score和最小的score两个值,标识当前用户数据的栈顶和栈底,后续用户通过传递这两个值的其中一个,并且告诉我们是上拉,还是下拉,我们就可以分页取对应的数据,数据图如下

步骤:

1. 用户第一次进入的时候,我们推荐给当前用户的数据是100到115的数据,首屏加载后端返回前端五条数据即110到115,同时返回前端两个score值drop(115)、up(110),前端展示对应数据的时候,同时存储这两个值,这个时候我们推荐给了用户116到124的数据,这个时候没有score值,直接使用`zrevrangeWithScores(customerId, 0,5)`,进行分页取值,

2. 用户如果执行了下拉动作,需要前端传递115这个score的值,同时告诉我们是下拉动作,我们会返回前端116到120的数据,同时返回前端两个score值drop(120)、up(116),这个时候前端应该更新本地缓存中的值,把drop更新为120,up保持110不变,目前前端一共显示10条数据,根据score值获取大于当前score值的数据,使用`zrangeByScoreWithScores(customerId, "115", "+inf")`

3. 如果用户执行了上拉动作,需要前端传递110这个score值,同时告诉我们是下拉动作,后端需要返回105到109的数据,同时返回前端两个score值drop(109)、up(105),这个时候前端应该更新本地缓存中的值,drop保持120,up更新为105,目前前端一共显示15条数据,根据score值获取小于当前score值的数据,使用`zrevrangeByScoreWithScores(customerId, "110", "-inf")`

4. 如果用户再一次下拉的时候,前端传递120这个score的值,其他的如2.。。。

原因:为什么需要根据score的来决定获取数据的位置,因为SortedSet中的值,随时有可能会增加和删除,虽然SortedSet本身是支持分页获取数据,但是这个列表随时可能增加或者删除数据,我们根据分页获取的数据,很可能和上次返回给前端的值是包含重复的。比如用户首屏加载了110到115的数据,如果这个时候我们没有给用户推荐数据,下次我们分页取的时候应该是105到109,但是我们把112从这个列表中删除了,那样就会取的是104到108这些数据,这样导致数据丢失。同样如果这个时候我们给用户推荐了116,这个时候上拉的时候分页取第二页的数据,那就取的是106到110,这样前端就会显示出重复的数据了

优化:如果自己站内的资源非常的庞大,并且会不停的推荐给用户,那就要做好定时清理数据的准备,避免SortedSet特别大的情况,我们可以每次在给用户推荐数据的时候,使用`ZCARD`,计算当前的列表的量,如果超过一定的量可以先删除一部分。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181102G1PV0G00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券