广告
返回顶部
首页 > 资讯 > 数据库 >如何使用Redis的有序集合实现排行榜功能
  • 260
分享到

如何使用Redis的有序集合实现排行榜功能

2024-04-02 19:04:59 260人浏览 薄情痞子
摘要

这篇文章给大家分享的是有关如何使用Redis的有序集合实现排行榜功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一个典型的游戏排行榜包括以下常见功能:能够记录每个玩家的分数;能

这篇文章给大家分享的是有关如何使用Redis的有序集合实现排行榜功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

一个典型的游戏排行榜包括以下常见功能:

  1. 能够记录每个玩家的分数;

  2. 能够对玩家的分数进行更新;

  3. 能够查询每个玩家的分数和名次;

  4. 能够按名次查询排名前N名的玩家;

  5. 能够查询排在指定玩家前后M名的玩家。

更进一步,上面的操作都需要在短时间内实时完成,这样才能最大程度发挥排行榜的效用。

由于一个玩家名次上升x位将会引起x+1位玩家的名次发生变化(包括该玩家),如果采用传统数据库(比如Mysql)来实现排行榜,当玩家人数较多时,将会导致对数据库的频繁修改,性能得不到满足,所以我们只能另想它法。

Redis作为NoSQL中的一员,近年来得到广泛应用。与Memcached相比,Redis拥有更多的数据类型和操作接口,具有更大的适用范围,其中的有序集合(sorted set,也称为zset)就非常适合于排行榜的构建。下面简要总结一下。

1. Redis的安装

ubuntu下安装Redis非常简单,执行如下命令即可:

$ sudo apt-get install redis-server

安装完毕,运行命令行客户端redis-cli就可以访问本地redis服务器

$ redis-cli
redis 127.0.0.1:6379>

如果要使用最新版本,需要到Redis官网(redis.io)下载最新的代码自行编译,步骤略。

2. ZSet的常用命令

有序集合首先是集合,其成员(member)具有唯一性,其次,每个成员关联了一个分数(score),使得成员可以按照分数排序。关于有序集合的介绍见redis.io/topics/data…,其命令见redis.io/commands#so…。

下面介绍几个能用于排行榜的命令。

假设lb为排行榜名称,user1、user2等为玩家唯一标识。

1) zadd——设置玩家分数

命令格式:zadd 排行榜名称 分数 玩家标识 时间复杂度:O(log(N))

下面设置了4个玩家的分数,如果玩家分数已经存在,则会覆盖之前的分数。

redis 127.0.0.1:6379> zadd lb 89 user1
(integer) 1
redis 127.0.0.1:6379> zadd lb 95 user2
(integer) 1
redis 127.0.0.1:6379> zadd lb 95 user3
(integer) 1
redis 127.0.0.1:6379> zadd lb 90 user4
(integer) 1

2) zscore——查看玩家分数

命令格式:zscore 排行榜名称 玩家标识 时间复杂度:O(1)
下面是查看user2这个玩家在lb排行榜中的分数。

redis 127.0.0.1:6379> zscore lb user2
“95”

3) zrevrange——按名次查看排行榜

命令格式:zrevrange 排行榜名称 起始位置 结束位置 [withscores] 时间复杂度:O(log(N)+M)

由于排行榜一般是按照分数由高到低排序的,所以我们使用zrevrange,而命令zrange是按照分数由低到高排序。

起始位置和结束位置都是以0开始的索引,且都包含在内。如果结束位置为-1则查看范围为整个排行榜。

带上withscores则会返回玩家分数。

下面为查看所有玩家分数。

redis 127.0.0.1:6379> zrevrange lb 0 -1 withscores

“user3”
“95”
“user2”
“95”
“user4”
“90”
“user1”
“89”

下面为查询前三名玩家分数。

redis 127.0.0.1:6379> zrevrange lb 0 2 withscores

“user3”
“95”
“user2”
“95”
“user4”
“90”

4) zrevrank——查看玩家的排名

命令格式:zrevrank 排行榜名称 玩家标识 时间复杂度:O(log(N))

与zrevrange类似,zrevrank是以分数由高到低的排序返回玩家排名(实际返回的是以0开始的索引),对应的zrank则是以分数由低到高的排序返回排名。

下面是查询玩家user3和user4的排名。

redis 127.0.0.1:6379> zrevrank lb user3
(integer) 0
redis 127.0.0.1:6379> zrevrank lb user1
(integer) 3

5) zincrby——增减玩家分数

命令格式:zincrby 排行榜名称 分数增量 玩家标识 时间复杂度:O(log(N))

有的排行榜是在变更时重新设置玩家的分数,而还有的排行榜则是以增量方式修改玩家分数,增量可正可负。如果执行zincrby时玩家尚不在排行榜中,则认为其原始分数为0,相当于执行zdd。

下面将user4的分数增加6,使其名次上升到第一位。

redis 127.0.0.1:6379> zincrby lb 6 user4
“96”
redis 127.0.0.1:6379> zrevrange lb 0 -1 withscores

“user4”
“96”
“user3”
“95”
“user2”
“95”
“user1”
“89”

6) zrem——移除某个玩家

命令格式:zrem 排行榜名称 玩家标识 时间复杂度:O(log(N))

下面移除玩家user4。

redis 127.0.0.1:6379> zrem lb user4
(integer) 1
redis 127.0.0.1:6379> zrevrange lb 0 -1 withscores

“user3”
“95”
“user2”
“95”
“user1”
“89”

7) del——删除排行榜

命令格式:del 排行榜名称

排行榜对象在我们首次调用zadd或zincrby时被创建,当我们要删除它时,调用redis通用的命令del即可。

redis 127.0.0.1:6379> del lb
(integer) 1
redis 127.0.0.1:6379> get lb
(nil)

3. 相同分数问题

免费的方案总有那么一些不完美。从前面的例子我们可以看到,user2和user3具有相同的分数,但在按分数逆序排序时,user3排在了user2前面。而在实际应用场景中,我们更希望看到user2排在user3前面,因为user2比user3先加入排行榜,也就是说user2先到达该分数。

但Redis在遇到分数相同时是按照集合成员自身的字典顺序来排序,这里即是按照”user2″和”user3″这两个字符串进行排序,以逆序排序的话user3自然排到了前面。

要解决这个问题,我们可以考虑在分数中加入时间戳,计算公式为:

带时间戳的分数 = 实际分数*10000000000 + (9999999999 – timestamp)

timestamp我们采用系统提供的time()函数,也就是1970年1月1日以来的秒数,我们采用32位的时间戳(这能坚持到2038年),由于32位时间戳是10位十进制整数(最大值4294967295),所以我们让时间戳占据低10位(十进制整数),实际分数则扩大10^10倍,然后把两部分相加的结果作为zset的分数。考虑到要按时间倒序排列,所以时间戳这部分需要颠倒一下,这便是用9999999999减去时间戳的原因。当我们要读取玩家实际分数时,只需去掉后10位即可。

初步看起来这个方案还不错,但这里面有两个问题。

第一个问题是小问题,采用秒为时间戳可能区分度还不够,如果同一秒出现两个分数相同的仍然会出现前面的问题,当然我们可以选择精度更高的时间戳,但在实际场景中,同一秒谁排前面已经无关紧要。

第二个问题是大问题,因为Redis的分数类型采用的是double,64位双精度浮点数只有52位有效数字,它能精确表达的整数范围为-2^53到2^53,最高只能表示16位十进制整数(最大值为9007199254740992,其实连16位也不能完整表示)。这就是说,如果前面时间戳占了10位的话,分数就只剩下6位了,这对于某些排行榜分数来说是不够用的。我们可以考虑缩减时间戳位数,比如从2015年1月1日开始计时,但这仍然增加不了几位。或者减少区分度,以分钟、小时来作为时间戳单位。

如果Redis的分数类型为int64,我们就没有上面的烦恼。说到这里,其实Redis真应该再额外提供一个int64类型的ZSet,但目前只能是幻想,除非自己改其源码

既然Redis也不能完美解决排行榜问题,那最终是不是有必要自己实现一个专门的排行榜数据结构呢?毕竟实际应用中的排行榜有很多可以优化的地方,比玩家呈金字塔分布,越是低分段玩家数量越多,同一分数拥有大量玩家,玩家增加一分都可能超越很多玩家,这就为优化提供了可能。

感谢各位的阅读!关于“如何使用Redis的有序集合实现排行榜功能”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

您可能感兴趣的文档:

--结束END--

本文标题: 如何使用Redis的有序集合实现排行榜功能

本文链接: https://www.lsjlt.com/news/56187.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何使用Redis的有序集合实现排行榜功能
    这篇文章给大家分享的是有关如何使用Redis的有序集合实现排行榜功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一个典型的游戏排行榜包括以下常见功能:能够记录每个玩家的分数;能...
    99+
    2022-10-18
  • java基于redis有序集合如何实现排行榜
    小编给大家分享一下java基于redis有序集合如何实现排行榜,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!前言排行榜作为互联网...
    99+
    2022-10-18
  • 使用Redis实现实时排行榜功能
    游戏中存在各种各样的排行榜,比如玩家的等级排名、分数排名等。玩家在排行榜中的名次是其实力的象征,位于榜单前列的玩家在虚拟世界中拥有无尚荣耀,所以名次也就成了核心玩家的追求目标。 一个...
    99+
    2022-11-12
  • 使用Redis实现排行榜功能的方法
    这篇文章给大家分享的是有关使用Redis实现排行榜功能的方法的内容。小编觉得挺实用的,因此分享给大家做个参考。一起跟随小编过来看看吧。下面由Redis教程栏目给大家介绍使用Redis实现排行榜功能的方法,希...
    99+
    2022-10-18
  • redis如何实现世界杯排行榜功能
    这篇文章主要介绍了redis如何实现世界杯排行榜功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。题外话:小编先给大家推荐一个不错的微信公众...
    99+
    2022-10-18
  • 使用redis怎么实现一个排行榜功能
    使用redis怎么实现一个排行榜功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。加入排行榜获取redis实例import redismain_rds...
    99+
    2023-06-15
  • Redis如何实现微信步数排行榜功能
    小编这次要给大家分享的是Redis如何实现微信步数排行榜功能,文章内容丰富,感兴趣的小伙伴可以来了解一下,希望大家阅读完这篇文章之后能够有所收获。1. 前言之前写过一篇博客,讲解的是Redis的5种数据结构...
    99+
    2022-10-18
  • 如何用Redis实现排行榜及相同积分按时间排序功能
    本篇内容主要讲解“如何用Redis实现排行榜及相同积分按时间排序功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何用Redis实现排行榜及相同积分按时间排序...
    99+
    2022-10-19
  • Redis如何实现排行榜及相同积分按时间排序功能
    这篇“Redis如何实现排行榜及相同积分按时间排序功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来...
    99+
    2022-10-19
  • 手把手教你使用redis实现排行榜功能
    目录一、需求背景二、实现思路  1、利用数据库2、利用Redis总结一、需求背景 最近项目需要做排行榜功能,实现员工邀请用户注册排行榜,要求是实时更新,查询要快。员工所属支行、二级行、省行,界面要根据条件显示排...
    99+
    2023-04-14
    redis 实现排行榜 redis做排行榜 redis 排行榜
  • Redis实现排行榜及相同积分按时间排序功能的实现
    目录不考虑积分相同积分相同按时间排序,排名唯一设计1设计2积分相同按时间排序,并列排名在日常的开发中,经常会碰到需要对用户的分值等进行排序,比如在游戏里面需要对战斗力进行排行,在组队活动中需要对各个队伍的贡献值进行排行,...
    99+
    2022-08-22
    Redis排行榜按时间排序 Redis时间排序 Redis相同积分按时间排序 Redis排行榜
  • 如何使用Redis和Ruby开发排行榜功能
    如何使用Redis和Ruby开发排行榜功能引言:在很多应用中,排行榜功能是一项常见的需求。无论是游戏中的玩家排名、音乐平台的歌曲排行,还是网站的热门帖子榜单,都需要实时的维护和展示排行榜数据。Redis是一款快速、高性能的内存数据库,而Ru...
    99+
    2023-10-22
    开发 redis Ruby
  • 如何利用redis实现排行榜的小秘诀
    这篇文章给大家分享的是有关如何利用redis实现排行榜的小秘诀的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。前言排行榜作为互联网应用中几乎必不可少的一个元素,其能够勾起人类自身对...
    99+
    2022-10-18
  • 【Redis面试题】如何使用Redis实现微信步数排行榜?
    1. 前言 之前写过一篇博客,讲解的是Redis的5种数据结构及其常用命令,当时有读者评论,说希望了解下这5种数据结构各自的使用场景,不过一直也没来得及写。 碰巧,在3月份找工作面试时,有个面试官先问了我Redis有哪几种数据结构...
    99+
    2018-04-12
    【Redis面试题】如何使用Redis实现微信步数排行榜?
  • Redis中有序集合的内部如何实现
    这篇“Redis中有序集合的内部如何实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Redis中有序集合的内部如何实现”文...
    99+
    2023-06-29
  • 如何使用MongoDB实现数据排序功能
    如何使用MongoDB实现数据排序功能引言:MongoDB是一种非关系型数据库,它以文档的形式组织数据,并且提供了丰富的查询操作。在实际应用中,数据的排序是非常常见的需求之一。本文将介绍如何使用MongoDB实现数据排序功能,并提供具体的代...
    99+
    2023-10-22
    MongoDB 实现 数据排序
  • 如何使用Comparator比较接口实现ArrayList集合排序
    目录使用Comparator比较接口实现排序Comparator接口定义如下我们定义一个“person”类创建按年龄排序的比较器实现Comparator接口使...
    99+
    2022-12-26
    使用Comparator比较接口 ArrayList集合排序 Comparator ArrayList集合排序
  • 如何使用PHP开发点餐系统的菜品推荐排行榜功能?
    如何使用PHP开发点餐系统的菜品推荐排行榜功能?随着互联网的发展,各种在线点餐系统正在变得越来越普及。为了提高用户体验和增加销量,菜品推荐排行榜功能成为了很多点餐系统的必备功能之一。那么,如何使用PHP开发点餐系统的菜品推荐排行榜功能呢?本...
    99+
    2023-11-02
    PHP 点餐系统 菜品推荐
  • Java如何使用 Lambda 表达式实现超强的排序功能
    这篇文章主要介绍Java如何使用 Lambda 表达式实现超强的排序功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!首先,我们定义一个基础类,后面我们将根据这个基础类演示如何在内存中排序。@Data@NoArgsC...
    99+
    2023-06-25
  • 如何使用MySQL和Java实现一个简单的排序算法功能
    如何使用MySQL和Java实现一个简单的排序算法功能导言:在软件开发中,排序算法是非常基础且常用的功能之一。本文将介绍如何使用MySQL和Java实现一个简单的排序算法功能,并提供具体代码示例。一、排序算法概述排序算法是将一组数据按照特定...
    99+
    2023-10-22
    排序算法 MySQL Java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作