NoSQL数据库(二)05-Redis数据类型——有序集合类型之介绍、命令-增加元素、获得元素的分数、获得排名在某个范围的元素列表、获得指定分数范围的元素、增加某个元素的分数
有序集合类型
介绍
有序集合类型(sorted set)的特点从它的名字中就可以猜到,它与上一节介绍的集合类型的区别就是“有序”二字。
在集合类型的基础上有序集合类型为集合中的每个元素都关联了一个分数,这使得我们不仅可以完成插入、删除和判断元素是否存在等集合类型支持的操作,还能够获得分数最高(或最低)的前N个元素、获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元素都是不同的,但是它们的分数却可以相同。 有序集合类型在某些方面和列表类型有些相似。
(1)二者都是有序的。
(2)二者都可以获得某一范围的元素。
但是二者有着很大的区别,这使得它们的应用场景也是不同的。
(1)列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问中间数据的速度会较慢,所以它更加适合实现如“新鲜事”或“日志”这样很少访问中间元素的应用。
(2)有序集合类型是使用散列表和跳跃表(Skip list)实现的,所以即使读取位于中间部分的数据速度也很快(时间复杂度是O(log(N)))。
(3)列表中不能简单地调整某个元素的位置,但是有序集合可以(通过更改这个元素的分数)。
(4)有序集合要比列表类型更耗费内存。
命令
- 增加元素
ZADD key score member [score member...]
ZADD 命令用来向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会用新的分数替换原有的分数。ZADD命令的返回值是新加入到集合中的元素个数(不包含之前已经存在的元素)。
假设我们用有序集合模拟计分板,现在要记录Tom、Peter和David三名运动员的分数(分别是89分、67分和100分):
redis> ZADD scoreboard 89 Tom 67 Peter 100 David (integer) 3
这时我们发现Peter的分数录入有误,实际的分数应该是76分,可以用ZADD命令修改Peter的分数:
redis> ZADD scoreboard 76 Peter (integer) 0
分数不仅可以是整数,还支持双精度浮点数:
redis> ZADD testboard 17E+307 a (integer) 1 redis> ZADD testboard 1.5 b (integer) 1 redis> ZADD testboard +inf c (integer) 1 redis> ZADD testboard -inf d (integer) 1
- 获得元素的分数
ZSCORE key member
redis> ZSCORE scoreboard Tom "89"
- 获得排名在某个范围的元素列表
ZRANGE key start stop [WITHSCORES]
ZREVRANGE key start stop [WITHSCORES]
ZRANGE命令会按照元素分数从小到大的顺序返回索引从 start到stop之间的所有元素(包含两端的元素)。ZRANGE命令与LRANGE命令十分相似,如索引都是从0开始,负数代表从后向前查找(−1表示最后一个元素)。就像这样:
redis> ZRANGE scoreboard 0 2 1) "Peter" 2) "Tom" 3) "David" redis> ZRANGE scoreboard 1 -1 1) "Tom" 2) "David"
如果需要同时获得元素的分数的话可以在 ZRANGE 命令的尾部加上 WITHSCORES 参数,这时返回的数据格式就从“元素1, 元素2, „, 元素n”变为了“元素1, 分数1, 元素2, 分数2, „, 元素n, 分数n”。
ZRANGE命令的时间复杂度为O(log n+m)(其中n为有序集合的基数,m为返回的元素个数)。
如果两个元素的分数相同,Redis会按照字典顺序(即"0"<“9”<“A”<“Z”<“a”<"z"这样的顺序)来进行排列。再进一步,如果元素的值是中文怎么处理呢?答案是取决于中文的编码方式,如使用UTF-8编码:
redis> ZADD chineseName 0 马华 0 刘墉 0 司马光 0 赵哲 (integer) 4 redis> ZRANGE chineseName 0 -1 1) "\xe5\x88\x98\xe5\xa2\x89" 2) "\xe5\x8f\xb8\xe9\xa9\xac\xe5\x85\x89" 3) "\xe8\xb5\xb5\xe5\x93\xb2" 4) "\xe9\xa9\xac\xe5\x8d\x8e"
可见此时Redis依然按照字典顺序排列这些元素。 ZREVRANGE命令和ZRANGE的唯一不同在于ZREVRANGE命令是按照元素分数从大到小的顺序给出结果的。
- 获得指定分数范围的元素
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
ZRANGEBYSCORE 命令参数虽然多,但是都很好理解。该命令按照元素分数从小到大的顺序返回分数在min和max之间(包含min和max)的元素:
redis> ZRANGEBYSCORE scoreboard 80 100 1) "Tom" 2) "David"
如果希望分数范围不包含端点值,可以在分数前加上“(”符号。例如,希望返回”80分到100分的数据,可以含80分,但不包含100分,则稍微修改一下上面的命令即可:
redis> ZRANGEBYSCORE scoreboard 80 (100 1) "Tom"
min和max还支持无穷大,同ZADD命令一样,-inf和+inf分别表示负无穷和正无穷。比如你希望得到所有分数高于80分(不包含80分)的人的名单,但你却不知道最高分是多少(虽然有些背离现实,但是为了叙述方便,这里假设可以获得的分数是无上限的),这时就可以用上+inf了:
redis> ZRANGEBYSCORE scoreboard (80 +inf 1) "Tom" 2) "David"
WITHSCORES参数的用法与ZRANGE命令一样,不再赘述。
了解 SQL 语句的读者对 LIMIT offset count 应该很熟悉,在本命令中 LIMIT offset count 与 SQL 中的用法基本相同,即在获得的元素列表的基础上向后偏移offset个元素,并且只获取前count个元素。为了便于演示,我们先向scoreboard键中再增加些元素:
redis> ZADD scoreboard 56 Jerry 92 Wendy 67 Yvonne (integer) 3
redis> ZRANGE scoreboard 0 -1 WITHSCORES 1) "Jerry" 2) "56" 3) "Yvonne" 4) "67" 5) "Peter" 6) "76" 7) "Tom" 8) "89" 9) "Wendy" 10) "92" 11) "David" 12) "100"
想获得分数高于60分的从第二个人开始的3个人:
redis> ZRANGEBYSCORE scoreboard 60 +inf LIMIT 1 3 1) "Peter" 2) "Tom" 3) "Wendy"
那么,如果想获取分数低于或等于 100 分的前 3 个人怎么办呢?这时可以借助ZREVRANGEBYSCORE命令实现。对照前文提到的ZRANGE命令和ZREVRANGE命令之间的关系,相信很容易能明白ZREVRANGEBYSCORE 命令的功能。需要注意的是ZREVRANGEBYSCORE 命令不仅是按照元素分数从大往小的顺序给出结果的,而且它的 min和max参数的顺序和ZRANGEBYSCORE命令是相反的。就像这样:
redis> ZREVRANGEBYSCORE scoreboard 100 0 LIMIT 0 3 1) "David" 2) "Wendy" 3) "Tom"
- 增加某个元素的分数
ZINCRBY key increment member
ZINCRBY 命令可以增加一个元素的分数,返回值是更改后的分数。例如,想给 Jerry加4分:
redis> ZINCRBY scoreboard 4 Jerry "60" redis> ZINCRBY scoreboard -4 Jerry "56"
ex: 实现按点击量排名
var redis = require('redis'); var client = new redis({
// 配置 }); var currentPage = 1; // 当前页面为1 var listLength = 10; var start = (currentPage - 1) * listLength; var end = currentPage * listLength - 1; // 0-9 var postID = client.zrevrange(`post:page.view ${
start} ${
end}`); // 递减 postID.forEach(id => {
client.hgetall(`post:${
id}`) });
如果需要按时间排序,只需修改文章存储时的分数为对应文章发布的Unix时间即可。
命令补充
- 获取集合中元素的数量
ZCARD key
redis> ZCARD scoreboard (integer) 6
- 获得指定分数范围内的元素个数
ZCOUNT key min max
redis> ZCOUNT scoreboard 90 100 (integer) 2 redis> ZCOUNT scoreboard (89 +inf (integer) 2
3.删除一个或多个元素
ZREM key member [member …]
ZREM命令的返回值是成功删除的元素数量(不包含本来就不存在的元素)。
redis> ZREM scoreboard Wendy (integer) 1 redis> ZCARD scoreboard (integer) 5
4.按照排名范围删除元素
ZREMRANGEBYRANK key start stop
ZREMRANGEBYRANK 命令按照元素分数从小到大的顺序(即索引 0表示最小的值)删除处在指定排名范围内的所有元素,并返回删除的元素数量。如:
redis> ZADD testRem 1 a 2 b 3 c 4 d 5 e 6 f (integer) 6 redis> ZREMRANGEBYRANK testRem 0 2 (integer) 3 redis> ZRANGE testRem 0 -1 1) "d" 2) "e" 3) "f"
5.按照分数范围删除元素
ZREMRANGEBYSCORE key min max
ZREMRANGEBYSCORE命令会删除指定分数范围内的所有元素,参数min和max的特性和ZRANGEBYSCORE命令中的一样。返回值是删除的元素数量。如:
redis> ZREMRANGEBYSCORE testRem (4 5 (integer) 1 redis> ZRANGE testRem 0 -1 1) "d" 2) "f"
6.获得元素的排名
ZRANK key member
ZREVRANK key member
ZRANK命令会按照元素分数从小到大的顺序获得指定的元素的排名(从0开始,即分数最小的元素排名为0)。如:
redis> ZRANK scoreboard Peter (integer) 0
ZREVRANK命令则相反(分数最大的元素排名为0):
redis> ZREVRANK scoreboard Peter (integer) 4
7.计算有序集合的交集
ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE
SUM|MIN|MAX] ZINTERSTORE命令用来计算多个有序集合的交集并将结果存储在destination键中(同样以有序集合类型存储),返回值为destination键中的元素个数。 destination键中元素的分数是由AGGREGATE参数决定的。
实例
z_demo.js
var redis = require('redis'); var client = new redis({
// 配置 }); // 实现点击量排名 post:page.view // zadd post:page.view 实现了一个点击量的有序集合 // 1. 排名 前十 2. 需要分页 var currentPage = 1; // 当前页面为1 var listLength = 10; var start = (currentPage - 1) * listLength; var end = currentPage * listLength - 1; // 0-9 // 一般排名要按降序 var postID = client.zrevrange(`post:page.view ${
start} ${
end}`); postID.forEach((id) => {
client.hgetall(`post:${
id}`, (data) => {
console.log('data', data) }) }) // 按时间排序 // 有序集合存储 我们的 时间戳
到此这篇NoSQL数据库(二)05-Redis数据类型——有序集合类型之介绍、命令-增加元素、获得元素的分数、获得排名在某个范围的元素列表、获得指定分数范围的元素、增加某个元素的分数的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/sqlbc/10807.html