Redis有序集合:成员唯一、分数可重及相关操作命令

Redis有序集合:成员唯一、分数可重及相关操作命令

Redis 的有序集合如同集合一样,是由 string 类型元素组成的集合,并且不允许有重复的成员。其区别在于,每个元素都与一个 double 类型的分数相关联。redis 依靠分数来对集合中的成员进行从小到大的排序。有序集合的成员是唯一的,然而分数(score)却可以重复。集合是通过两种底层数据结构来实现的。一种数据结构是 ziplist 压缩列表,另一种是 redis 中最为经典的数据结构 skipList 跳跃表。正因如此,在进行添加、删除和查找操作时,其复杂度均为 O(1)。并且,集合中所能容纳的最大成员数为 232 - 1,也就是 4294967295,这意味着每个集合能够存储 40 多亿个成员。添加命令 zadd 键 [nx|xx] [CH] [INCR] 分值 成员 [分值 成员...]

在有序集合里添加元素,若元素已存在,就会更新其 score;要是该有序集合不存在,就直接创建并添加对应的元素;倘若 key 不是 sorted set 类型,就会报错。

分数score 为双精度的浮点型数字字符串。

NX:不更新存在的成员。只添加新成员;

XX:仅更新存在的成员,不添加新成员;

如果成员不存在就进行添加操作,如果成员存在就更新其分值,然后返回分值发生变化的成员总数;对于分数没有变化的情况不进行计算。

当指定这个选项时,命令等同于 zincrby 命令,会对成员的分数进行递增操作,并且会返回操作后的分值

[id_111436033]
[id_1807789562].0[id_1103517049]:6379> zadd english_score 60 zhangsan 70 lisi 90 wangwu
(integer) 3
127.0.0.1:6379> zrange english_score 0 -1 withscores
1) "zhangsan"
2) "60"
3) "lisi"
4) "70"
5) "wangwu"
6) "90"
//NX:不更新存在的成员。只添加新成员
//张三已存在,所以返回0
127.0.0.1:6379> zadd english_score nx 70 zhangsan
(integer) 0
127.0.0.1:6379> zadd english_score nx 60 xiaoming
(integer) 1
//XX:仅更新存在的成员,不添加新成员
127.0.0.1:6379> zadd english_score xx 60 zhaoliu
(integer) 0
127.0.0.1:6379> zadd english_score xx 70 zhangsan
(integer) 0
//张三存在分数改为70,赵六不存在无操作
127.0.0.1:6379> zrange english_score 0 -1 withscores
1) "xiaoming"
2) "60"
3) "lisi"
4) "70"
5) "zhangsan"
6) "70"
7) "wangwu"
8) "90"
如果成员不存在就进行添加操作,如果成员存在就更新其分值,然后返回分值发生变化的成员总数;对于分数不变的情况不进行计算。
//张三分数改为80,添加赵六分数为75.5
127.0.0.1:6379>[id_752908027]80 zhangsan 75.5 zhaoliu
(integer) 1
127.0.0.1:6379> zrange english_score 0 -1 withscores
 1) "xiaoming"
 2) "60"
 3) "lisi"
 4) "70"
 5) "zhaoliu"
 6) "75.5"
 7) "zhangsan"
 8) "80"
 9) "wangwu"
10) "90"
指定这个选项时,命令就相当于 zincrby 命令,会对成员的分数进行递增操作,然后返回操作后的分值。
//张三分数+5
127.0.0.1:6379> zadd english_score incr 5 zhangsan
"85"
127.0.0.1:6379> zrange english_score 0 -1 withscores
 1) "xiaoming"
 2) "60"
 3) "lisi"
 4) "70"
 5) "zhaoliu"
 6) "75.5"
 7) "zhangsan"
 8) "85"
 9) "wangwu"
10) "90"

查询命令 zcard key

获取有序集合的成员数

127.0.0.1:6379> zcard english_score
(integer) 3

zscore key member

返回有序集中,成员的分数值

127.0.0.1:6379> zscore english_score lisi
"70"

递增类型

从键 key 中获取索引范围为 start 到 stop 的元素 [WITHSCORES]

按分值递增的顺序进行排序,通过索引区间来返回有序集合中指定区间内的成员,并且输出结果会带有分数(withscores)

127.0.0.1:6379> zrange english_score 0 -1 
1) "zhangsan"
2) "lisi"
3) "wangwu"
127.0.0.1:6379> zrange english_score 0 -1 withscores
1) "zhangsan"
2) "60"
3) "lisi"
4) "70"
5) "wangwu"
6) "90"

zrangebylex 表示按照字典序范围获取集合中的元素。它需要指定键名 key ,以及最小和最大的字典序范围 min 和 max 。还可以通过 LIMIT 子句来限制返回结果的偏移量 offset 和数量 count 。

通过字典区间返回有序集合的成员。

字典中排序位置较小的成员,开头需为“[”或“(”,可用“-”来代替

字典中排序位置较大的成员,开头要么是“[”,要么是“(”,也可以用“+”来代替

返回结果是否分页。在指令中包含 LIMIT 时,必须输入 offset 和 count。

offset:返回结果起始位置

count:返回结果数量

注意:

不要在分数不一致的 SortSet 集合中使用 ZRANGEBYLEX 指令。因为获取的结果不准确,成员字符串是以二进制数组的字节数进行比较的,默认按 ASCII 字符集的顺序排列,若成员字符串包含 utf-8 这类字符集的内容,就会影响返回结果,所以建议不要使用。默认情况下,“max”参数前必须加“[”符号开头,且“[”符号与成员之间不能有空格;“min”参数前也必须加“[”符号开头,“[”符号与成员之间不能有空格。返回的成员结果集会包含“min”和“max”参数。“max”参数前可以加“(”符号开头表示小于,“(”符号与成员之间不能有空格;“min”参数前也可以加“(”符号开头表示小于,“(”符号与成员之间不能有空格。返回的成员结果集不会包含“max”和“min”这两个成员。能够用“-”来表示得分的最小值,用“+”来表示得分的最大值。“min”和“max”不能颠倒,若“max”放在前面而“min”放在后面,就会致使返回结果为空。与 ZRANGEBYLEX 获取顺序相反的指令是 ZREVRANGEBYLEX。源码使用 C 语言的 memcmp()函数,对字符从第 0 位开始一直到最后一位进行排序。倘若前面部分是相同的,那么较长的字符串相较于较短的字符串,其排序会靠后。

127.0.0.1:6379> ZADD myzset 0 a 0 b 0 c 0 d 0 e 0 f 0 g
(integer) 7
127.0.0.1:6379> ZRANGEBYLEX myzset - [c
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> ZRANGEBYLEX myzset - (c
1) "a"
2) "b"
127.0.0.1:6379> ZRANGEBYLEX myzset [aaa (g
1) "b"
2) "c"
3) "d"
4) "e"
5) "f"

使用 zrangebyscore 命令,指定键为 key,分数范围为 min 到 max ,可以选择包含分数 [WITHSCORES] ,还可以限制偏移量为 offset 和数量为 count [LIMIT offset count] 。

按分值递增排序,通过分数区间返回有序集合指定区间内的成员

127.0.0.1:6379> zrangebyscore english_score 60 80 withscores
1) "xiaoming"
2) "60"
3) "lisi"
4) "70"
5) "zhaoliu"
6) "75.5"

zrank key member

有序集成员按照分数值从小到大进行排序,然后返回在这个有序集合中指定成员的排名索引。

127.0.0.1:6379> zrange english_score 0 -1 
1) "xiaoming"
2) "lisi"
3) "zhaoliu"
4) "zhangsan"
5) "wangwu"
//zhangsan的索引是3
127.0.0.1:6379> zrank english_score zhangsan
(integer) 3

递减类型是 zrevrange 命令,它用于获取指定 key 范围内的元素,范围从 start 到 stop ,可以选择包含元素的分数信息 [WITHSCORES] 。

通过索引来返回有序集中的成员,这些成员处于指定区间内,并且按照分值递减的顺序进行排序,分数从高到低

127.0.0.1:6379> zrevrange english_score 0 -1 withscores
 1) "wangwu"
 2) "90"
 3) "zhangsan"
 4) "85"
 5) "zhaoliu"
 6) "75.5"
 7) "lisi"
 8) "70"
 9) "xiaoming"
10) "60"

使用 zrevrangebyscore 命令,指定键为 key,最大分数为 max,最小分数为 min,可选择包含分数 [WITHSCORES],还可指定偏移量 offset 和数量 count [LIMIT offset count]

返回指定分数区间内有序集的成员,这些成员按分值递减排序,即从高到低排序

127.0.0.1:6379>使用 zrevrangebyscore 命令来获取 english_score 的相关数据。80 70 withscores
1) "zhaoliu"
2) "75.5"
3) "lisi"
4) "70"

zrevrank key member

有序集成员按照分数值从大到小的顺序进行排序,然后返回在这个有序集合中指定成员的排名索引。

127.0.0.1:6379> zrevrange english_score 0 -1 
1) "wangwu"
2) "zhangsan"
3) "zhaoliu"
4) "lisi"
5) "xiaoming"
 127.0.0.1:6379>查询 zrevrank 关于 english_score 的信息,结果是 zhangsan。
(integer) 1
127.0.0.1:6379> zrevrank english_score lisi
(integer) 3

删除命令是 zrem 以及键 key 和成员 member 等(member 可以有多个)。

移除有序集合中的一个或多个成员

127.0.0.1:6379> zrevrange english_score 0 -1
1) "wangwu"
2) "zhangsan"
3) "zhaoliu"
4) "lisi"
5) "xiaoming"
127.0.0.1:6379> zrem english_score xiaoming
(integer) 1
127.0.0.1:6379> zrevrange english_score 0 -1
1) "wangwu"
2) "zhangsan"
3) "zhaoliu"
4) "lisi"

zremrangebylex key min max

移除有序集合中给定字典区间的所有成员,然后返回被成功移除的成员的数量,这里要注意不包括被忽略的成员。具体的命令是 zremrangebyrank key start stop 。

移除给定键 key 中排名在 min 到 max 之间的所有成员 zremrangebyscore key min max

移除有序集合中给定的分数区间的所有成员 运算命令

zcount key min max

计算在有序集合中指定区间分数的成员数

127.0.0.1:6379> zrevrange english_score 0 -1 withscores
1) "wangwu"
2) "90"
3) "zhangsan"
4) "85"
5) "zhaoliu"
6) "75.5"
7) "lisi"
8) "70"
//80-90分的有两个,张三和王五
127.0.0.1:6379> zcount english_score 80 90
(integer) 2

zlexcount key min max

在有序集合中计算指定字典区间内成员数量

127.0.0.1:6379> ZADD myzset 0 a 0 b 0 c 0 d 0 e
(integer) 5
127.0.0.1:6379> ZADD myzset 0 f 0 g
(integer) 2
127.0.0.1:6379> ZLEXCOUNT myzset - +
(integer) 7
127.0.0.1:6379> ZLEXCOUNT myzset [b [f
(integer) 5

zincrby key increment member

有序集合中对指定成员的分数加上增量 increment

可以传递一个负数值 increment ,这样就能让分数减去相应的值。例如,使用 ZINCRBY key -5 member 这个操作,就可以让 member 的 score 值减去 5 。

当 key 不存在时,ZINCRBY key increment member 等同于 ZADD key increment member ;当分数不是 key 的成员时,ZINCRBY key increment member 也等同于 ZADD key increment member 。

当 key 不是有序集类型时,返回一个错误。

分数值可以是整数值或双精度浮点数。

127.0.0.1:6379> zincrby english_score 0.5 zhaoliu
"76"

并且可以指定聚合操作 [AGGREGATE SUM|MIN|MAX] 来决定交集结果的聚合方式。

计算给定的一个或多个有序集的交集,需用 numkeys 参数指定给定 key 的数量,然后将交集(结果集)储存到 destination 。

在默认的情况下,结果集中某一个成员的分数值,是由所有给定集之下该成员的分数值相加而得到的总和。

使用 WEIGHTS 选项时,你能够为每个特定的有序集分别设定一个乘法因子。每个给定有序集的所有成员的 score 值,在传递给聚合函数之前,都需要先与该有序集的因子相乘。

使用 AGGREGATE 选项,你能够指定并集的结果集的聚合方式。

默认所使用的参数为 SUM 时,能够把所有集合里某个成员的 score 值进行求和,以此作为结果集中该成员的 score 值;当使用参数 MIN 时,能够把所有集合中某个成员的最小 score 值当作结果集中该成员的 score 值;而参数 MAX 是把所有集合中某个成员的最大 score 值作为结果集中该成员的 score 值。

//有序集 mid_test
127.0.0.1:6379> ZADD mid_test 70 "Li Lei"
(integer) 1
127.0.0.1:6379> ZADD mid_test 70 "Han Meimei"
(integer) 1
127.0.0.1:6379> ZADD mid_test 99.5 "Tom"
(integer) 1
//另一个有序集 fin_test
127.0.0.1:6379> ZADD fin_test 88 "Li Lei"
(integer) 1
127.0.0.1:6379> ZADD fin_test 75 "Han Meimei"
(integer) 1
127.0.0.1:6379> ZADD fin_test 99.5 "Tom"
(integer) 1
//交集
127.0.0.1:6379> ZINTERSTORE sum_point 2 mid_test fin_test
(integer) 3
//显示有序集内所有成员及其分数值
127.0.0.1:6379> ZRANGE sum_point 0 -1 WITHSCORES     
1) "Han Meimei"
2) "145"
3) "Li Lei"
4) "158"
5) "Tom"
6) "199"

使用 zunionstore 命令创建一个名为 destination 的聚合结果集,指定 numkeys 个键,这些键可以是 key [key …] ,可以设置权重为 WEIGHTS weight ,聚合操作可以是 SUM|MIN|MAX 中的一种。

计算给定的一个或多个有序集的并集,需用 numkeys 参数指定给定 key 的数量,然后将该并集(结果集)储存到 destination 。

在默认的情况下,结果集中某一个成员的分数值,是由所有给定集之下该成员的分数值相加而得到的。

127.0.0.1:6379> zadd zset1 1 one 2 two
(integer) 2
127.0.0.1:6379> zadd zset2 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zunionstore out 2 zset1 zset2 WEIGHTS 2 3
(integer) 3
127.0.0.1:6379> zrange out 0 -1 withscores
1) "one"
2) "5"
3) "three"
4) "9"
5) "two"
6) "10"

skiplist

它本质上是一种查找结构,其作用是解决算法中的查找问题,能够依据给定的 key 迅速查找到其所在位置,是对有序链表的一种优化,查找的效率通常为 O(logn)。

例子:

在普通有序链表里查找一个数据时,我们需要从开头开始查找,其时间复杂度比普通链表要高,是 O(n)。倘若我们每隔一个数据生成一个新的链表,那么当我们要查找 23 时,流程如下:

23 先与 7 进行比较,接着与 19 进行比较,23 比 7 和 19 都大,然后继续往后进行比较。

当 23 和 26 进行比较时,23 比 26 小。所以要回到下面的链表(原链表),然后与 22 进行比较。

2.3 比 22 大。接着沿着下面的指针继续向后与 26 进行比较。23 比 26 小。这表明待查数据 23 在原链表中不存在,并且它的插入位置应当在 22 和 26 之间。

因为有了新增的指针,所以我们无需逐个与链表中的节点进行比较。我们可以先进行跳跃式的比较,以此来缩小比较的范围,然后再进行查找,这样提高了查找的效率。在二层之上,我们还能够添加三层、四层,skiplist 正是基于这样的启发而诞生的一种数据结构。

为了便于插入节点,skiplist 不要求上下相邻两层链表的节点个数有严格的对应关系。它会针对每个节点随机生成一个层数。以下是一个 skiplist 的生成过程。

若要在这样的跳表查找23,流程如下:

在最上层进行查找,找到了 7,接着往右找,发现没有 null 了;然后在 7 节点的下一层继续往右找,找到了 37,将其与目标值比较,发现比 37 小;再在 37 节点的下一层往左找,找到了 19,将其与目标值比较,发现比 19 大;接着在 19 节点向下,再往右找,找到了 22,将其与目标值比较,发现比 22 大;之后在 22 向右找,找到了 26,将其与目标值比较,发现比 26 小;所以 23 就在 22 和 26 之间插入。

你可能想看:
« 上一篇
下一篇 »

相关推荐

FreeBasic:强大免费开源的64位basic编译器及应用优势

2025年05月10日

82阅读

脊柱侧弯矫正方法大盘点:运动康复、支具矫正等多种方式

2025年05月09日

88阅读

如何在winForm标题栏去掉标题文字且任务栏图标正常显示

2025年05月09日

86阅读

十一黄金周促销广告词大全,国庆购物狂欢等你来

2025年05月09日

78阅读

关闭快速编辑模式及插入模式,设置控制台指定文字颜色举例

2025年05月09日

63阅读

黄金搭档低糖高钙饮品包装及成分功效全解析,适合人群要知晓

2025年05月09日

91阅读