如何高效获取用户未浏览过的高赞userPosts列表?Redis方案咨询
高效获取未浏览高赞帖子的实现方案
针对你遇到的问题,结合Redis特性和通用思路,提供以下几种高效实现方式:
Redis专属方案
1. 利用Redis 6.2+的ZDIFF LIMIT特性(最优)
Redis 6.2及以上版本支持在ZDIFF命令中直接使用LIMIT参数,可在服务端完成「主有序集合与用户已浏览集合的差集计算」+「截取前N条高赞结果」的操作,完全避免客户端过滤的开销。
假设主有序集合键为userPosts:top(score为点赞数,成员为post ID),用户已浏览集合键为user:{uid}:viewed(存储用户看过的post ID),执行命令:
ZDIFF 1 userPosts:top user:{uid}:viewed WITHSCORES LIMIT 0 20
该命令直接返回用户未浏览的前20条高赞帖子(带点赞数),所有计算在Redis端完成,网络传输仅返回最终需要的数据。
2. 低版本Redis的替代方案(ZDIFFSTORE+ZRANGE)
如果你的Redis版本低于6.2,可通过临时存储差集的方式实现:
# 计算差集并存储到临时有序集合 ZDIFFSTORE temp:unviewed:{uid} 1 userPosts:top user:{uid}:viewed # 获取前20条结果 ZRANGE temp:unviewed:{uid} 0 19 WITHSCORES # 删除临时集合 DEL temp:unviewed:{uid}
这种方式虽然多了两步操作,但仍比客户端过滤高效,因为差集计算在Redis端完成,避免了大量无效数据的网络传输。
3. Lua脚本自定义遍历逻辑(灵活适配)
如果需要更灵活的控制(比如动态调整预取数量),可以用Lua脚本在Redis原子执行遍历逻辑,直到收集到20条未浏览帖子:
-- 参数说明:KEYS[1] = 主有序集合键,KEYS[2] = 用户已浏览集合键;ARGV[1] = 目标数量(20),ARGV[2] = 预取数量(比如50) local top_posts = redis.call('ZRANGE', KEYS[1], 0, tonumber(ARGV[2])-1, 'WITHSCORES') local viewed_map = {} -- 将已浏览集合转为哈希表,O(1)查询 for _, post_id in ipairs(redis.call('SMEMBERS', KEYS[2])) do viewed_map[post_id] = true end local result = {} local collected = 0 -- 遍历预取的帖子,筛选未浏览的 for i = 1, #top_posts, 2 do local post_id = top_posts[i] local score = top_posts[i+1] if not viewed_map[post_id] then table.insert(result, post_id) table.insert(result, score) collected = collected + 1 if collected >= tonumber(ARGV[1]) then break end end end return result
调用脚本时可以根据用户已浏览数量动态调整预取数(比如已浏览多的用户预取50条,少的预取30条),平衡性能和资源消耗。
通用方案(不依赖Redis特性)
预取+本地缓存
每次从主集合预取比目标数量更多的帖子(比如取50条),在本地过滤已浏览内容后,将未浏览的帖子缓存起来(缓存有效期设为5分钟,匹配主集合的更新周期)。后续请求优先从缓存中取,缓存不足时再去主集合拉取新的批次。这种方式减少了和存储层的交互次数,同时避免了每次都过滤大量已浏览内容。
注意事项
- 用户已浏览集合建议用Redis的Set结构,因为
SISMEMBER查询是O(1),比Hash更高效。 - 主集合每5分钟更新时,无需主动同步用户的未浏览状态,因为所有方案都是基于实时的主集合和已浏览集合计算差集,天然适配排序更新。
内容的提问来源于stack exchange,提问作者qubicswap.com
相关产品推荐
相关产品推荐

