通知一下_左手MongoDB,右手Redis_宠文网
首页

通知一下

关灯 护眼    字体:

上一章 章节列表 下一页




有序集合(Sorted Set)是Redis的一个数据结构。

有序集合里面的数据跟集合一样,也是不能重复的,但是每一个元素又关联了一个分数(Score),根据这个分数可以对元素进行排序。分数可以重复。



9.3.1 实例39:实现排行榜功能


各种排行榜是我们司空见惯的功能。各位读者是否思考过,各种排行榜是如何实现的呢?

实例描述

分别使用MongoDB和Redis的有序集合来实现排行榜功能。对比传统数据库的排序功能,寻找有序集合实现排序功能的优点。

1.使用传统数据库实现排行榜

这里以 MongoDB 为例来进行说明。这种方法的逻辑非常直接,需要被排名的信息都保存在数据库里面,当需要显示排行榜时,直接读取数据库,然后对结果进行排名。

(1)运行rank_data_to_mongo.py生成测试数据,如图9-15所示。测试数据的user_id对应于用户的id,score对应于用户的积分。

图9-15 测试数据

(2)根据积分对用户进行排序。代码如下:

代码9-15 使用MongoDB对用户积分排序

(3)运行效果如图9-16所示。

图9-16 直接使用MongoDB进行排序

2.使用数据库排序的弊端

具体到一个实际例子,比如说直播网站观众向主播送礼物的排行版,如果直接在数据库里面进行排序,弊端有以下几点:

● 排行榜会实时更新,数据每一次变化都要排序,会对数据库的性能造成影响。

● 频繁更新数据,导致数据库性能下降。

● 数据量太大时排序时间缓慢。

● 对被排序字段添加索引会占用更多空间。

3.使用有序集合进行排序

Redis的有序集合天生就自带排序的功能。

(1)直接把MongoDB中的数据导入到Redis中名为“rank”的有序集合中:

代码9-16 使用有序集合排序



(2)显示某一个特定用户的排名,具体代码如下:

代码9-17 显示特定排名的用户

(3)显示全部用户的排名,具体代码如下:

rank = client.zrevrank('rank', 0, 10000, withscores=True)

(4)运行效果如图9-17所示。

图9-17 排名查询

有序集合还能直接修改某一个值的分数,从而直接改变排序。



9.3.2 实例40:使用Python读写有序集合


有序集合的操作命令有二十多个,对应到Python中也有二十多个方法。本书选择其中常用的几个。

实例描述

在Python中控制Redis,读写有序集合,实现以下功能:

(1)把数据添加到有序集合中。

(2)修改有序集合值的评分。

(3)将有序集合基于“评分”进行排序。

(4)将有序集合基于“位置”进行排序。

(5)根据值查询排名和评分情况。

1.向有序集合添加数据

向有序集合添加数据,使用的方法为“zadd”。它的格式有两种:

方法一:client.zadd(’有序集合名’, 值1, 评分1, 值2, 评分2, 值n, 评分n)

方法二:client.zadd(’有序集合’, 值1=评分1, 值2=评分2, 值3=评分3)

这两种方式的效果是一样的,但是第1种的值可以使用变量,而第2种的值不能使用变量。

例如,代码9-18是一个和年龄相关的有序集合。

代码9-18 使用Python向Redis有序集合中添加数据

其中,主要代码说明如下。

● 第4行代码:其中的name1和name2是变量,它们里面的值分别为“王小二”和“张三”。最后存在Redis中的值也是“王小二”和“张三”。

● 第5行代码:使用Value=score的写法,用这种写法时,Value不能使用变量,只能直接写值。

第4行和第5行效果完全一样。

2.修改评分

修改评分使用的方法名为“zincrby”,格式如下:

client.zincrby(’有序集合名’, 值,改变量)

例如,在age_rank中,把“王小二”的年龄增加三岁,把“小明”的年龄减0.5岁:

代码9-19 修改有序集合的元素评分

3.对有序集合元素基于评分范围进行排序

根据评分范围进行排序,使用的方法分别为“zrangebyscore”和“zrevrangebyscore”。

这两个方法的用法完全相同,差别在于:

● zrangebyscore根据评分按照从小到大的顺序排序。

● zrevrangebyscore根据评分按照从大到小的顺序排序。

它们的使用格式如下:

client.zrangebyscore(’有序集合名’, 评分上限, 评分下限, 结果切片起始位置, 结果数量, withscores=False)

client.zrevrangebyscore(’有序集合名’, 评分上限, 评分下限, 结果切片起始位置, 结果数量, withscores=False)

其中,评分上限、评分下限用于确定排序的范围。例如,评分分布在0~10000,现在只对评分在10~100范围内的值进行排序。排序完成以后,通过设定结果切片的起始位置、结果数量来限定返回的列表的长度。其中,结果切片起始位置、结果数量这两个参数可以同时省略,省略表示返回排序后的所有数据。 />
提示:

如果withscores设置为False,则返回的结果直接是排序好的值。

如果withscores设置为True,则返回的列表里面的元素是元组。元组的第1个元素是值,第2个元素是评分。

举例,在有序集合rank中,对积分在10~100范围内的人员进行倒序排序,并返回前3条数据,代码如下:

client.zrevrangebyscore('rank', 100, 10, 0, 3)

运行效果如图9-18所示。

图9-18 对积分10~100范围内数据倒序并取前3条

4.对有序集合基于位置进行排序

基于位置范围进行排序,用到的方法名为“zrange”和“zrevrange”。

● zrange对评分按照从小到大的顺序排序。

● zrevrange对评分按照从大到小的顺序排序。

它们的用法如下:

client.zrange(’有序集合名’, 开始位置(含), 结束位置(含), desc=False, withscores=False)

client.zrevrange(’有序集合名’, 开始位置(含), 结束位置(含), withscores=False)

这两个方法,根据0开始的索引找到需要排序的元素范围,然后对这个范围内的数据进行排序。

(1)zrange方法。

如果使用的是zrange方法,则位置“0”是评分最小的元素,位置“1”是评分次小的元素,以此类推。

假设开始位置写为“0”,结束位置写为“4”,则取出最小的5个元素,如图9-19所示。

图9-19 使用zrange取最小5个元素

提示:

与Python列表一样,开始位置和结束位置也可以写为负数,表示从后往前数。

例如,开始位置写为“−4”,结束位置写为“−1”,表示取评分最大的4个元素,且score低的在前,如图9-20所示。

图9-20 使用zrange取最大4个元素

(2)zrevrange方法。

使用zrevrange方法,位置“0”为最大的元素,位置“1”为次大的元素。

如果开始位置写“0”,结束位置写“4”,则取最大的5个元素,如图9-21所示。

图9-21 使用zrevrange取最大5个元素

如果开始位置取“-4”,结束位置取“-1”,则取最小的4个元素,且score高的在前,如图9-22所示。

图9-22 使用zrevrange取最小4个元素

提示:

如果使用zrange方法,同时desc=True,那在底层会自动调用zrevrange方法。因此,如果使用zrange,开始位置为“0”,结束位置为“4”,参数desc=True,则它的作用是取最大的5个元素, 如图9-23所示。千万不要认为是取最小的5个元素再倒序排序。

图9-23 使用zrange并且desc为True

如果withscores为False,则返回的结果直接是排序好的值;如果withscores为True,返回的列表里面的元素是元组,每个元组的第1个元素是值,第2个元素是评分。

5.根据值查询排名,根据值查询评分

(1)使用zrank和zrevrank方法,可以查询一个值在有序列表中的排名。格式如下:

client.zrank(’有序列表名’, ’值’)

client.zrevrank(’有序列表名’, ’值’)

① 使用zrank方法时。

● 如果值存在,则返回值的排名。排名是从0开始的,评分越小则排名越靠近0,评分最小的值的排名为0。

● 如果值不存在,则返回None。

② 使用zrevrank方法时。

● 如果值存在,则返回值的排名。排名是从0开始的,评分越大排名越靠近0,评分最大的值的排名为0。

● 如果值不存在,则返回None。

(2)使用zscore可以查询一个值的评分。格式如下:

client.zscore(’有序列表名’, ’值’)

如果值不存在,则返回None。

6.其他常用方法

(1)查询有序集合里面一共有多少个值,使用的方法名为“zcard”。

格式如下:

client.zcard(’有序集合名’)

如果有序集合不存在,则返回0。

(2)查询在某个评分范围内的值有多少,使用的方法名为zcount。

格式如下:

client.zcount(’有序集合名’, 评分下限, 评分上限)



9.3.3 实例41:在Redis交互环境redis-cli中使用有序集合


实例描述

在redis-cli中读写有序集合,实现以下功能:

(1)添加数据。

(2)修改值的评分。

(3)基于评分和位置进行排序。

(4)查询值的排名和评分。

有序集合在redis-cli中,有一些命令的参数与Python中存在差别,需要特别注意。

1.添加数据

添加数据对应的命令为“zadd”,命令格式如下:

zadd 有序集合名 评分1 值1 评分2 值2 评分n 值n

注意,在redis-cli中,添加数据时“评分在前,值在后”;在Python中,添加数据时“值在前,评分在后”。

2.修改评分

修改评分使用的命令为“zincrby”,命令格式如下:

zincrby 有序集合名 修改的分数 值

如果值不存在,则自动创建,并把修改的分数作为初始评分。

举例:需要在有序集合age_rank中,把王小二的年龄增加10岁,则命令应该写为:

zincrby age_rank 10 王小二

运行效果如图9-24所示。

图9-24 在redis-cli中修改评分

3.基于评分范围排序,基于位置范围排序

基于评分范围排序,使用的命令为“zrangebyscore”和“zrevrangebyscore”。

基于位置范围排序,使用的命令为“zrange”和“zrevrange”。

命令格式为:

zrangebyscore 有序列表名 评分下限 评分上限 WITHSCORES LIMIT 切片开始位置 结果数量

zrevrangebyscore 有序列表名 评分下限 评分上限 WITHSCORES LIMIT 切片开始位置 结果数量

其中,WITHSCORES和LIMIT都是关键字。

● WITHSCORES可以省略。省略以后,只有值没有评分。

● 如果不需要对结果进行切片,则“LIMIT 切片开始位置 结果数量”也可以省略。

zrange 有序集合名 开始位置 结束位置

zrevrange 有序集合名 开始位置 结束位置 WITHSCORES

4.查询值的排名,查询值的评分

● 查询排名使用的命令为“zrank”和“zrevrank”,命令格式如下:

zrank 有序集合名 值

zrevrank 有序集合名 值

● 查询值的评分命令为“zscore”,命令格式如下:

zscore 有序集合名 值

5.其他常用命令

● 查询有序集合中元素的个数,使用的命令为“zcard”,命令格式如下:

zcard 有序集合名

● 查询评分范围内的元素个数,用到的命令为“zcount”,命令格式如下:

zcount 有序集合名 积分下限 积分上限


    

上一章 章节列表 下一页