有序集合篇

Redis有序集合(Sorted sets)包含一组按浮点分数排序的唯一成员。与集合一样,你可以添加、获取或移除单个成员,并执行集合操作,如联合、相交、集合差和计算卡入度。此外,您还可以根据分数或成员值查询集合,对结果进行聚合、过滤和排序。

redis-sorted-sets

场景

有序集合使用的场景非常多,下面列举了一些常用的业务场景。

排行榜

排行榜是有序集合非常容易实现的功能,例如按照用户的分数、积分或其他指标来排名。

  • 比如用户积分排行
// 添加用户的积分
$redis->zAdd('user:score:rank', 1, '用户ID_1');
$redis->zAdd('user:score:rank', 2, '用户ID_2');
$redis->zAdd('user:score:rank', 10, '用户ID_3');
$redis->zAdd('user:score:rank', 8, '用户ID_4');

// 获取积分在0 ~ 11的排名前10用户.
$redis->zRangeByScore('user:score:rank', 0, 11, ['limit' => [0, 10]]);
//  ['用户ID_1', '用户ID_2', '用户ID_4', '用户ID_3']

// 获取积分在0 ~ 11的排名前10用户以及积分
$redis->zRangeByScore('user:score:rank', 0, 11, ['withscores' => true, 'limit' => [0, 10]]);
//  ['用户ID_1' => 1, '用户ID_2' => 2, '用户ID_4' => 8, '用户ID_3' => 10]

zRangeByScore 默认是score值从小到大,如果需要从大到小可以使用zRevRangeByScore

时间轴

在社交应用中,可以使用有序集合来实现用户的时间轴,其中时间戳作为score,内容作为member,这样就可以按时间顺序获取用户的动态,还有就是公司或者品牌历程。

// 添加用户Id为1的集合
$redis->zAdd('user:timeline:1',  1111111111, '出生了');
$redis->zAdd('user:timeline:1',  2222222222, '6岁了');
$redis->zAdd('user:timeline:1',  3333333333, '小学毕业了');

范围查找

由于有序集合的member参数是按照score排序的,因此可以非常高效地进行范围查找,比如找出某个范围内的member,或者根据score范围获取一定数量的成员。


// 获取数学成绩等于100的学生
$redis->zRangeByScore('mathematics', 100, 100);
// 获取数学成绩在90 ~ 99的学生
$redis->zRangeByScore('mathematics', 90, 99);
// 获取数学未及格的学生数量
$redis->zCount('mathematics', 0, 59);

实时热门内容

通过记录某条内容的点击量、浏览量等指标作为score条件值,可以实时地获取当前热门的内容。

$redis->zAdd('hot:news',  0, '新闻ID_1');
// 浏览了 -> 给`新闻ID_1`的score加1
$redis->zIncrBy('hot:news', 1, '新闻ID_1');
// 点击了 -> 给`新闻ID_1`的score加2
$redis->zIncrBy('hot:news', 2, '新闻ID_1');

任务调度

可以使用有序集合来实现任务调度,例如按照任务的执行时间作为score,定时触发执行。


$time = time();

// 获取小于等于当前时间的任务 
$tasks = $redis->zRevRangeByScore('tasks', $time, 0);

foreach ($tasks as $task) {
    // todo
}

范围之间的关系

有序集合还可以用来处理范围之间的关系,比如找出两个范围的交集、并集或差集。

// 比如两个用户的共同好友, 以添加好友的时间为score, member为好友ID

$redis->zAdd('user:1', 1111111111, '1000');
$redis->zAdd('user:1', 1111111112, '1001');
$redis->zAdd('user:1', 1111111113, '1002');
$redis->zAdd('user:1', 1111111114, '1004');
$redis->zAdd('user:1', 1111111115, '1008');

$redis->zAdd('user:2', 2111111115, '1008');
$redis->zAdd('user:2', 2111111119, '1002');
$redis->zAdd('user:2', 3111111119, '1009');

// 将共同好友存储大`user:union:12`中
$count = $redis->zInterStore('user:union:12', ['user:1', 'user:2']); 
// 获取共同好友列表
$redis->zRange('user:union:1', 0, $cuont);

最大/最小值查找

通过有序集合提供的zPopMinzPopMax,可以快速地找出最大值或最小值,而不需要遍历整个集合。


// 获取最高分学生
$redis->zPopMax('mathematics', 1);
// 获取最低分学生
$redis->zPopMin('mathematics', 1);

流行度统计

可以使用有序集合来统计各种对象的流行度,比如文章、商品等,通过增加或减少score来反映对象的流行程度。(这个和实时热门内容类似)

协作

如果你有更多的场景使用用例,可以通过github提交pr请求。有问题可以开issue编辑此页面