排行榜功能是一个很普遍的需求。使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择。

一般排行榜都是有实效性的,比如“用户积分榜”。如果没有实效性一直按照总榜来排,可能榜首总是几个老用户,对于新用户来说,那真是太令人沮丧了。

首先,来个“今日积分榜”吧,排序规则是今日用户新增积分从多到少。

那么用户增加积分时,都操作一下记录当天积分增加的有序集合。
假设今天是 2015 年 04 月 01 日,UID 为 1 的用户因为某个操作,增加了 5 个积分。
Redis 命令如下:

ZINCRBY rank:20150401 5 1

假设还有其他几个用户也增加了积分:

ZINCRBY rank:20150401 1 2
ZINCRBY rank:20150401 10 3

看看现在有序集合 rank:20150401 中的数据(withscores 参数可以附带获取元素的 score):

ZRANGE rank:20150401 0 -1 withscores
1) "2"
2) "1"
3) "1"
4) "5"
5) "3"
6) "10"

按照分数从高到低,获取 top10:

ZREVRANGE rank:20150401 0 9 withscores
1) "3"
2) "10"
3) "1"
4) "5"
5) "2"
6) "1"

因为只有三个元素,所以就查询出了这些数据。

如果每天记录当天的积分排行榜,那么其他花样百出的榜单也就简单了。
比如“昨日积分榜”:

ZREVRANGE rank:20150331 0 9 withscores

利用并集实现多天的积分总和,实现“上周积分榜”:

ZUNIONSTORE rank:last_week 7 rank:20150323 rank:20150324 rank:20150325 rank:20150326 rank:20150327 rank:20150328 rank:20150329 WEIGHTS 1 1 1 1 1 1 1

这样就将 7 天的积分记录合并到有序集合 rank:last_week 中了。权重因子 WEIGHTS 如果不给,默认就是 1。为了不隐藏细节,特意写出。
那么查询上周积分榜 Top10 的信息就是:

ZREVRANGE rank:last_week  0 9 withscores

“月度榜”、“季度榜”、“年度榜”等等就以此类推。

下面给出一个 PHP 版的简单实现。使用 Redis 依赖于 PHP 扩展 PhpRedis,代码还依赖于 Carbon 库,用于处理时间。代码量很少,所以就不敲注释了。

 
<?php

namespace Blog\Redis;

use \Redis;
use Carbon\Carbon; class Ranks { const PREFIX = 'rank:'; protected $redis = null; public function __construct(Redis $redis) {
$this->redis = $redis;
} public function addScores($member, $scores) {
$key = self::PREFIX . date('Ymd');
return $this->redis->zIncrBy($key, $scores, $member);
} protected function getOneDayRankings($date, $start, $stop) {
$key = self::PREFIX . $date;
return $this->redis->zRevRange($key, $start, $stop, true);
} protected function getMultiDaysRankings($dates, $outKey, $start, $stop) {
$keys = array_map(function($date) {
return self::PREFIX . $date;
}, $dates); $weights = array_fill(0, count($keys), 1);
$this->redis->zUnion($outKey, $keys, $weights);
return $this->redis->zRevRange($outKey, $start, $stop, true);
} public function getYesterdayTop10() {
$date = Carbon::now()->subDays(1)->format('Ymd');
return $this->getOneDayRankings($date, 0, 9);
} public static function getCurrentMonthDates() {
$dt = Carbon::now();
$days = $dt->daysInMonth; $dates = array();
for ($day = 1; $day <= $days; $day++) {
$dt->day = $day;
$dates[] = $dt->format('Ymd');
}
return $dates;
} public function getCurrentMonthTop10() {
$dates = self::getCurrentMonthDates();
return $this->getMultiDaysRankings($dates, 'rank:current_month', 0, 9);
} }

 

使用 Redis 实现排行榜功能的更多相关文章

  1. Redis实现排行榜功能(实战)

    需求前段时间,做了一个世界杯竞猜积分排行榜.对世界杯64场球赛胜负平进行猜测,猜对+1分,错误+0分,一人一场只能猜一次.1.展示前一百名列表.2.展示个人排名(如:张三,您当前的排名106579). ...

  2. redis实现排行榜功能

    目录 加入排行榜 操作排行榜 redis的zset可以很方便地用来实现排行榜功能,下面简单介绍python如何使用redis实现排行榜功能 加入排行榜 获取redis实例 import redis m ...

  3. 使用 Redis 实现排行榜功能 (转载 https://segmentfault.com/a/1190000002694239)

    排行榜功能是一个很普遍的需求.使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择. 一般排行榜都是有实效性的,比如"用户积分榜".如果没有实效性一直按照总榜来排,可能榜 ...

  4. Redis实现世界杯排行榜功能(实战)

    转载请注明出处:https://www.cnblogs.com/wenjunwei/p/9754346.html 需求 前段时间,做了一个世界杯竞猜积分排行榜.对世界杯64场球赛胜负平进行猜测,猜对+ ...

  5. Redis 有序聚合实现排行榜功能

    排行榜功能是一个很普遍的需求.使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择.Redis有序集合非常适用于有序不重复数据的存储 一般排行榜都是有实效性的,比如“用户积分榜”.如果没有实 ...

  6. Redis的Sorted-Sets排行榜功能实现

    Redis的ZSet排行榜功能实现 1. 功能需求 类似给用户n张图片, 用户左滑不喜欢右滑喜欢.所以每个用户就会有一些喜欢的图片集合和不喜欢的图片集合.现在我们要做一个将按照一个算法将喜欢的排到前面 ...

  7. 用户积分排行榜功能-Redis实现

    一.排行榜功能简介 排行榜功能是一个很普遍的需求.使用 Redis 中有序集合(SortedSet)的特性来实现排行榜是又好又快的选择. 一般排行榜都是有实效性的,比如交通数据流中的路口/路段的车流量 ...

  8. 【接口设计】用户积分排行榜功能-Redis实现

    一.排行榜功能简介 排行榜功能是一个很普遍的需求.使用 Redis 中有序集合(SortedSet)的特性来实现排行榜是又好又快的选择. 一般排行榜都是有实效性的,比如交通数据流中的路口/路段的车流量 ...

  9. Redis多机功能介绍

    Redis多机功能目的:以单台Redis服务器过渡到多台Redis服务器 Redis单机在生产环境中存在的问题 1.内存容量不足 Redis使用内存来存书数据库中的数据,但是对于一台机器来说,硬件的内 ...

随机推荐

  1. 夏夏的php开发笔记开写啦

    主要写一些平时drupal.dedecms.帝国cms.wordpress等php程序开发过程中遇到的问题,以及解决的过程,记录夏夏的成长,把握契机,创造未来

  2. CF Round #367 C题

    题目 链接:http://codeforces.com/contest/706/problem/C 好像又是DP... dp[i][0]表示第i个字符串不翻转成字典序排列的花费,dp[i][1]表示第 ...

  3. required - HTML5里的input标签的required属性提示文字修改

    input 里面增加这样的语句: <input type="text" placeholder="您的姓名" required oninvalid=&qu ...

  4. 上个项目的一些反思 III

    离线缓存 之前的项目因为实时性要求比较高,所以一打开客户端,就开始做网络请求.现在想想,是没有做内容的离线缓存.这个问题,我没意识到.产品经理也没有意识到... 我觉得Archiver,来做比较合适, ...

  5. erlang 分布式数据库Mnesia 实现及应用

    先推荐一篇:mnesia源码分析(yufeng)   - linear hash   ETS/DETS/mnesia 都使用了linear hash算法 http://en.wikipedia.org ...

  6. Linux下多线程下载利器 axel

    参考 https://teddysun.com/377.html 使用示例: axel -an https://ubuntu-mate.org/raspberry-pi/ubuntu-mate-16. ...

  7. MySQL 保留字

    ADD ALL ALTER ANALYZE AND AS ASC ASENSITIVE BEFORE BETWEEN BIGINT BINARY BLOB BOTH BY CALL CASCADE C ...

  8. XP机器上WCF采用X509证书加密时IIS读取证书的授权

    XP机器上WCF采用X509证书加密时IIS读取证书的授权 XP下的授权命令为:winhttpcertcfg -g -c LOCAL_MACHINE\My -s 证书名称 -a "ASPNE ...

  9. MVC Code First 自动生成数据库

    1.新建一个MVC项目

  10. "_OBJC_CLASS_$_CMMotionManager", referenced from:

    好久没写随笔了,今日项目爆红.如下: 缺少系统库 CoreMotion.framework, 在Build Phases -> Link Binary With Libraries 中添加即可.