oop vue网站模板 vue开发教程 vue添加class 后台管理ui jq去空格 jquery选择器找子元素 css获取最后一个元素 jquery清除子元素 mysql小数用什么类型 linux自动获取ip oracle可视化工具 javaweb是前端还是后端 matlab输入参数太多 cmd清空命令 java高级特性 安装mysql 数据库查询 python断言assert实例 python自学教材 python支持中文 javafinally java如何使用 java流程 nginx安装教程 python开发实例 莫愁脚本 电视免费软件 战地联盟辅助 vfloppy 脚本大全 msn格式 管理文件 jdk9下载 电脑书籍下载 proteus8 极限防守图 驱动精灵绿色版 沉沦之城 igfxtray
当前位置: 首页 > 学习教程  > 编程学习

redis存储微博点赞的人,如何存储?

2021/1/9 2:07:45 文章标签: 微博取消赞

问题对人有帮助,内容完整,我也想知道答案 3问题没有实际价值,缺少关键内容,没有改进余地 比如说有一个微博的TID是1。 UID为1,2,3,4,5,6,7,8,9的用户都给这个微博点赞了。用redis缓存框架存储的话如何存储。微博可能有…

3

比如说有一个微博的TID是1。 UID为1,2,3,4,5,6,7,8,9的用户都给这个微博点赞了。用redis缓存框架存储的话如何存储。微博可能有几十万个。如果用

key->set(value) 这种形式的话 key是微博ID的标示 value是 [1,2,3,4,5,6,7,8,9]这种形式,这样的话有多少个微博就有多少个K-V存储。我想知道这样会有什么弊端吗?或者有什么更好的方法吗?

  • redis
  • 链接 
  • 评论 
默认排序 时间排序

3 个回答

6
滕亦飞 1.3k  1月15日 回答 · 1月15日 更新

可以采用多个HashSet存储。每一条微博只是HashSet内的一个子key。增加赞的数量可以采用HIncrBy命令。把TID分块,使得每个HashSet内的key不超过100个。官方文档表示HashSet在内部元素小于一百个的时候采用线性存储与扫描,跟同数据规模下树形结构相比效率更高,更省内存。

例如:TID为123456的微博存在z:1234的HashSet中,其key为56。假设最新的微博活跃程度也较高,那么绝大多数情况下被调用的HashSet只有区区几个,对CPU的缓存很友好。

如果要管理赞的用户,可以自定义数据格式。在用户数量少的时候把用户列表整个内嵌到HashSet的值域中。用户超过比如50人后将其单独整理出一个Set,在HashSet里保存Set的key。例:

# 内嵌UID的情况
hget z:1234 56
> "1,2,3,4"...

# 使用set的情况
hget z:1234 56
> "UIDlist:10"
smembers UIDlist:10
> 1) "1"
> 2) "2"
> ...

由于绝大多数微博赞的用户均比较少,HashSet可以节省出不少全局空间的key(全局key比HashSet的key更耗内存)。

关于 @卖掉内裤去上网 的回答:
若采用in-place quicksort,50个用户的手动排序效率非常高,因为在这个数据规模下数据紧密存放带来的缓存友好性远胜于Redis ZSet相对于手动排序带来的提升。而赞的用户升上去后就会自动适应成set或者zset,保证算法时间复杂度。如果还担心效率,可以把排序好的UID列表重新写回HashSet的一个value中,以后没有数据改变的话直接使用。

究竟采用set还是zset还是要看楼主的需求。set加入一个成员的复杂度为O(1),zset是O(log N),但set就没有排序功能了。

  • 链接 
  • 17 评论 
4
卖掉内裤去上网 877  1月15日 回答 · 1月15日 更新

不太推荐LS用HASH来存储点赞的数据. 因为没办法进行排序(如果需要的话. 我想一定需要)

目前 我们是这样处理的.

可以使用ZSET有序集合进行存储. 理论上说一个ZSET中, 10W以内的数量并无任何鸭梨. 也就是说一条微博点赞的人数再10W以内(这是不可能的).

$redis->ZADD("t:$tid:liked", time(), $uid); //$tid 为你的微博ID, $uid 为你的点赞人的UID


//取出点赞的人(支持按照点赞时间来排序的哦:)).. 按照LSD的说的 HASH取出来的值没有任何顺序的.
$uids = $redis->ZREVRANGE("t:$tid:liked", $offset, $max, TRUE); //倒序取值
$uids = $redis->ZRANGE("t:$tid:liked", $offset, $max, TRUE); //顺序取值

//$offset 和 $max 这样来算
$pagesize = 20;
$offset = ($page > 1) ? ($page - 1) * $pagesize : 0;
$max = ($page * $pagesize) - 1;

//一次性取出所有的这样取.
$total = $redis->ZCARD("t:$tid:liked");
$uids = $redis->ZREVANGE("t:$tid:liked", 0, $total - 1, TRUE);

//拿到的$uids 是一个array 哦..

//判断一个用户是否点赞了这一来哦
$redis->ZSCORE("t:$tid:liked", $uid);
//取消赞这样来
$redis->ZREM("t:$tid:liked", $uid);

//批量取消某短时间内的点赞这样操作
$redis->ZREMRANGEBYSCORE("t:$tid:liked", $start_timestamp, $end_timestamp);

//诸如此类的操作, 要比HASH强很多. 

恩再PS一下!!!

如果需要用到NOSQL这样的数据库来存储类似微博的数据的话, 可以这样存储:).

$pipe = $redis->MULTI(Redis::PIPELINE);
$pipe->SET("t:$tid", json_encode($data)) //json这种格式存储貌似有点废物. 如果能想到更好的格式的话,不要用JSON, 因为JSON太大了.. 比如MSGPACK这个个是就比JSON要好很多
     ->ZADD("t:scores", time(), $tid);
$pipe->EXEC();

//PIPE 这样的操作赞爆了. 如果你的REDIS支持事务的话, PIPE就不是一个原子性的操作了

//取出数据的话就很好取出了!! 
$tid = $reids->ZREVRANGE("t:scores", 0, 100);
$pipe = $redis->MULTI(Redis::PIPELINE); 
foreach($tid as $key=> $value){
    $pipe->GET("t:$value");
}
$list = $pipe->EXEC();

//$list就是你的数据啦

再再PS一下, 微博评论也是类似的存储方法. 只是需要约定$redis KEYS的名称. 比如:
c:<评论ID> 怎么和微博数据关联起来可以这样:

t:$tid:comments:scores (ZSET timestmap 评论ID);

这样取数据的时候就用PIPELINE方便很多了.

最后啰嗦一句, NOSQL这种数据库的 KEY 一定要设置好.

  • 链接 
  • 9 评论 
0
yuankui 23  1月21日 回答 · 1月21日 更新
  1. 保存每个uid是否有必要,还是你觉得新浪微博就是这么搞的?大多数情况,其实大家只是关注一个数字,如果这样的话,那么用一个数字来存储就可以了{tid->count}

  2. 如果非要保存,建议还是用{tid->set(uid)}来保存

  3. 有个优化就是你可以设定一个阈值,比如超过100人点赞,就不再往里面加东西了,而仅仅加一个数字(当然这里需要你再存一个{tid->count})。因为超过1w的微博点赞,没人回去逐个把每个点赞的人都点开的。。

  • 链接 
  • 2 评论 

本文链接: http://www.dtmao.cc/news_show_1100311.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?