redis - 如何使用 Redis 实现临时排行榜?

标签 redis

使用 Redis,使用排序集实现记分板很简单,但我不确定如何使用滚动时间窗口(即 30/60/90 天窗口)实现记分板。

由于排序集条目没有任何时间成分,实现基于时间的排行榜的最佳方式是什么?

最佳答案

您可以仔细考虑以下两种通用方法(即需要填写详细信息;):

1) 使用 Redis 的 ZSET(有序集)的小数特性来存储时间和用户的(?)分数(例如,整数部分可以是时间戳,小数部分是分数)。时间戳部分的范围可以给您时间效果,但为了排序,您必须重置纪元值的“LSB”。

2) 使用不同的排行榜,每个滚动窗口一个,并定期或在接触数据库时维护它们。

第一种方法更简单,但您可能会遇到极端情况(例如, float 据类型的限制、巨大的 ZSET...),因此如果这是一个问题,您应该考虑提前对您的排行榜进行分区。

编辑 - 更多示例: 假设您的排行榜的键是 k并且您正在跟踪 term1。天真地,当 term1 命中时,你会做:

ZADD k <epoch> <epoch>:term1

这将为您提供每个术语命中 1 秒的解决方案,但您需要更多,并且以这种方式保持计数没有意义。所以,让我们假设 <epoch*>总是凌晨 12 点。不要单独计算每个术语的命中率,而是像这样汇总它:

escore = ZSCORE k:<epoch*> term1
if (escore == nil):
    escore = 0

ZADD k:<epoch*> escore+1 term1

在滚动窗口中聚合,例如30天,决定k:<epoch*>:30d<epoch*> 之间所有日期的汇总和 <epoch*> -30天。所以每一个 term1点击,你会做类似的事情:

# initialize today's rolling window if it doesn't exist
if not(EXISTS k:<epoch*>:30d):
    ZUNIONSTORE k:<epoch*>:30d 29 k:<epoch*>-1d ... k:<epoch*>-29d AGGREGATE SUM

rscore = ZSCORE k:<epoch*>:30d term1
if (rscore == nil):
    rscore = 0

ZADD k:<epoch*>:30d rscore+1 term1

这实际上是我对第二种方法的意思,所以是的,您将保留 30 个 key (只要记住在不再需要它们时删除/使它们过期)。

第一种方法包括对所有内容使用单个 k ZSET。假设您的术语计数可以达到 10000,请考虑以下针对每个术语计数和汇总执行的伪操作:

escore = ZSCORE k <epoch*>:term1
rscore = ZSCORE k <epoch*>:30d:term1
if (escore == nil):
    escore = <epoch*>

if (rscore == nil):
    rscore = <epoch*>
    for (i=1; i++; i<30):
        rscore += fractional(ZSCORE k <epoch* - i*days>:term1)

ZADD k escore+1/10000 <epoch*> + ':term1'
ZADD k rscore+1/10000 <epoch*> + ':30d:term1'

此设计使用单个 k存储所有汇总,其中分数的整数部分是纪元(允许您做范围),小数部分是计数器 (% 10000)。

关于redis - 如何使用 Redis 实现临时排行榜?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25706925/

相关文章:

ruby-on-rails - 如何在 Redis 对象 gem 中使用 hash_key?

redis - Redisson CacheConfig中ttl和maxIdletime有什么区别

api - Redis Booksleeve——如何正确使用Hash API

Laravel 广播不写入 redis 但直接调用 redis 工作

ruby - Redis 在 sinatra rake 任务中不工作

spring - 使用 Spring Redis key 安全吗?

php - Session 和 Laravel Queues 可以使用同一个 Redis 实例吗?

c# - 使用 C# 更新 Redis 中的值

redis - 如何通过 CloudFormation 模板将 Redis AUTH token 添加到 ElastiCache?

c# - IRedisClient.As<T>() 在幕后做了什么?