关于Ruby on Rails 3:Redis zrevrangebyscore,按字典顺序排序

Redis zrevrangebyscore, sorting other than lexicographical order

我已经在Redis中使用排序集实现了排行榜。我希望按时间顺序对得分相同的用户进行排序,即排名第一的用户应排名更高。当前,redis支持字典顺序。有没有一种方法可以覆盖它。手机号码被用作排序集中的成员。

我想到的一种解决方案是在移动电话号码前面添加时间戳,并维护一个散列以映射移动电话号码和时间戳。

1
2
3
$redis.hset('mobile_time', '1234567890',"#{Time.now.strftime('%y%m%d%H%M%S')}")
pref = $redis.hget('mobile_time, '1234567890'')
$redis.zadd('myleaderboard',"1234567890:#{pref}")

这样,在任何情况下,我都可以通过从哈希添加前缀来获得给定用户的排名。

现在这不是我想要的。这将与我想要的相反。早到的用户将被置于晚到的用户下方(两者得分均相同)。

1
2
Key for user1 = 201210121953**23**01234567890    score: 400
key for user2 = 201210121253**26**09313123523    score: 400 (3 seconds later)

如果我使用zrevrangebyscore,则将user2放置在高于user1的位置。

但是,有一种方法可以获取所需的排名:

1
2
users_with_higher_score_count = $redis.zcount("mysset","(400","+inf")
users_with_same_score = $redis.zrangebyscore("mysset","400","400")

现在,我具有正确顺序的列表users_with_same_score。查看索引,我可以计算出用户的排名。

获得排行榜。我可以以50个间隔获取成员,并通过ruby代码对其进行排序。但这似乎不是一个好方法。

我想知道是否有更好的方法可以做到这一点。或可以在我打算的解决方案中进行的任何改进。

在此先感谢您的帮助。

附言分数是50的倍数


排序集中的分数支持双精度浮点数,因此可能更好的解决方案是将redis分数存储为highscore.timestamp

例如 (伪代码)

1
2
3
highscore = 100
timestamp = now()
redis.zadd('myleaderboard', highscore + '.' + timestamp, playerId)

这意味着获得相同高分的多个玩家也将根据其获得高分的时间进行排序,如下所示:

对于玩家1 ...

1
redis.zadd('myleaderboard', '100.1362345366',"Charles")

对于玩家2 ...

1
redis.zadd('myleaderboard', '100.1362345399',"Babbage")

有关更多详细信息,请参见此问题:Redis排行榜的独特得分


如果您以得分的降序显示排行榜,那么我认为上述解决方案将行不通。 不仅要在分数中附加timestamp,还应附加Long.MAX_VALUE - System.nanoTime(),因此最终分数代码应类似于-

1
2
3
highscore = 100
timestamp = Long.MAX_VALUE - System.nanoTime();
redis.zadd('myleaderboard', highscore + '.' + timestamp, playerId);

现在,当您致电redis.zrevrange('myleaderboard', startIndex, endIndex)时,您将获得正确的订单


sort命令的外部权重功能是您的救星

1
SORT mylist BY weight_*

http://redis.io/commands/sort