一、有序集合(sorted set)
有序集合和集合类似,只是说它是有序的,和无序集合的主要区别在于每一个元素除了值之外,它还会多一个分数。
分数是一个浮点数,在 Java 中是使用双精度表示的,根据分数, Redis 就可以支持对分数从小到大或者从大到小的排序
和无序集合一样,对于每一个元素都是唯一的 ,但是对于不同元素而言,它的分数可以一样
元素也是 String 数据类型,也是一种基于 hash 的存储结构。
集合是通过哈希表实现的,所以添加、删除、 查找的复杂度都是 0(1)
集合中最大的成员数为 2的32次方减 1 ( 40 多亿个成员)
1.1 ZADD(zadd)
向有序集合添加一个或多个成员,或者更新已存在成员的分数
Redis Zadd 命令用于将一个或多个成员元素及其分数值加入到有序集当中。
如果某个成员已经是有序集的成员,那么更新这个成员的分数值,并通过重新插入这个成员元素,来保证该成员在正确的位置上。
分数值可以是整数值或双精度浮点数。
如果有序集合 key 不存在,则创建一个空的有序集并执行 ZADD 操作。
当 key 存在但不是有序集类型时,返回一个错误。
注意: 在 Redis 2.4 版本以前, ZADD 每次只能添加一个元素。
语法
127.0.0.1:6379> ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
- XX: 仅仅更新存在的成员,不添加新成员。
- NX: 不更新存在的成员。只添加新成员。
- CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。
注:在通常情况下,ZADD返回值只计算新添加成员的数量。
INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
分数可以精确的表示的整数的范围:
Redis 有序集合的分数使用双精度64位浮点数。我们支持所有的架构,这表示为一个IEEE 754 floating point number,它能包括的整数范围是-(2^53) 到 +(2^53)。或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。
可以版本:>= 1.2.0
返回值:被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员;成员的新分数(双精度的浮点型数字)字符串。
案例
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myzadd 98 j3_liuliang 92 xiaowang #添加数据 (integer) 2 127.0.0.1:6379> zrange myzadd 0 -1 #返回集合数据,不带 score 这个值 1) "xiaowang" 2) "j3_liuliang" 127.0.0.1:6379> zrange myzadd 0 -1 withscores #返回集合数据,带 score 这个值 1) "xiaowang" 2) "92" 3) "j3_liuliang" 4) "98" 127.0.0.1:6379>
1.2 ZRANGE(zrange)
通过索引区间返回有序集合成指定区间内的成员
返回存储在有序集合key中的指定范围的元素。 返回的元素可以认为是按得分从最低到最高排列。 如果得分相同,将按字典排序。
当你需要元素从最高分到最低分排列时,请参阅ZREVRANGE(相同的得分将使用字典倒序排序)。
参数start和stop都是基于零的索引,即0是第一个元素,1是第二个元素,以此类推。 它们也可以是负数,表示从有序集合的末尾的偏移量,其中-1是有序集合的最后一个元素,-2是倒数第二个元素,等等。
start和stop都是全包含的区间,因此例如ZRANGE myzset 0 1将会返回有序集合的第一个和第二个元素。
超出范围的索引不会产生错误。 如果start参数的值大于有序集合中的最大索引,或者start > stop,将会返回一个空列表。 如果stop的值大于有序集合的末尾,Redis会将其视为有序集合的最后一个元素。
可以传递WITHSCORES选项,以便将元素的分数与元素一起返回。这样,返回的列表将包含value1,score1,...,valueN,scoreN,而不是value1,...,valueN。 客户端类库可以自由地返回更合适的数据类型(建议:具有值和得分的数组或记录)。
语法
127.0.0.1:6379> ZRANGE key start stop [WITHSCORES]
可以版本:
>= 1.2.0
返回值:
给定范围内的元素列表(如果指定了WITHSCORES
选项,将同时返回它们的得分)。
案例
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myzadd 98 j3_liuliang 92 xiaowang #添加数据 (integer) 2 127.0.0.1:6379> zrange myzadd 0 -1 #返回指定区间数据 1) "xiaowang" 2) "j3_liuliang" 127.0.0.1:6379> zrange myzadd 0 -1 withscores #返回带 score 得数据 1) "xiaowang" 2) "92" 3) "j3_liuliang" 4) "98" 127.0.0.1:6379> zrange myzadd 0 -2 withscores 1) "xiaowang" 2) "92" 127.0.0.1:6379> zrange myzadd 0 -3 withscores #指定区间没有数据就返回空 (empty list or set) 127.0.0.1:6379>
1.3 ZRANK(zrank)
返回有序集合中指定成员的排名(索引)
返回有序集key中成员member的排名。其中有序集成员按score值递增(从小到大)顺序排列。排名以0为底,也就是说,score值最小的成员排名为0。
使用ZREVRANK命令可以获得成员按score值递减(从大到小)排列的排名。
语法
127.0.0.1:6379> ZRANK key member
可以版本:
>= 2.0.0
返回值:
如果成员是有序集 key 的成员,返回 member 的排名。 如果成员不是有序集 key 的成员,返回 nil 。
案例
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myzadd 98 j3_liuliang 92 xiaowang 59 laoli #添加数据 (integer) 3 127.0.0.1:6379> zrange myzadd 0 -1 withscores #返回所有数据,由小到大 1) "laoli" 2) "59" 3) "xiaowang" 4) "92" 5) "j3_liuliang" 6) "98" 127.0.0.1:6379> zrank myzadd laoli #由小到大,返回 0 说明倒数第一 (integer) 0 127.0.0.1:6379>
1.4 ZREM(zrem)
移除有序集合中的一个或多个成员
Redis Zrem 命令用于移除有序集中的一个或多个成员,不存在的成员将被忽略。
当 key 存在但不是有序集类型时,返回一个错误。
注意: 在 Redis 2.4 版本以前, ZREM 每次只能删除一个元素。
语法
127.0.0.1:6379> ZREM key member [member ...]
可以版本:>= 1.2.0
返回值:被成功移除的成员的数量,不包括被忽略的成员。
案例
127.0.0.1:6379> zrange myzadd 0 -1 withscores #查看数据 1) "laoli" 2) "59" 3) "xiaowang" 4) "92" 5) "j3_liuliang" 6) "98" 127.0.0.1:6379> zrem myzadd laoli #把第 0 位数据删除 (integer) 1 127.0.0.1:6379> zrange myzadd 0 -1 withscores #查看数据 1) "xiaowang" 2) "92" 3) "j3_liuliang" 4) "98" 127.0.0.1:6379>
1.5 ZCARD(zcard)
获取有序集合的成员数
Redis Zcard 命令用于计算集合中元素的数量。
语法
127.0.0.1:6379> ZCARD KEY_NAME
可以版本:>= 1.2.0
返回值:当 key 存在且是有序集类型时,返回有序集的基数。 当 key 不存在时,返回 0 。
案例
127.0.0.1:6379> zrange myzadd 0 -1 withscores #添加数据 1) "xiaowang" 2) "92" 3) "j3_liuliang" 4) "98" 127.0.0.1:6379> zcard myzadd #查看key中元素得个数 (integer) 2 127.0.0.1:6379>
1.6 ZCOUNT(zcount)
计算在有序集合中指定区间分数的成员数
Redis Zcount 命令用于计算有序集合中指定分数区间的成员数量。
语法
127.0.0.1:6379> ZCOUNT key min max
可以版本:>= 2.0.0
返回值:分数值在 min 和 max 之间的成员的数量。
案例
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myzset 99 j3_liuliang 89 xiaowng 75 laoli 57 xiaoming #添加数据 (integer) 4 127.0.0.1:6379> zcount myzset 100 80 (integer) 0 127.0.0.1:6379> zcount myzset 80 100 #分数再100 到 80分之间得人数 (integer) 2 127.0.0.1:6379> zcount myzset 80 10 (integer) 0 127.0.0.1:6379>
1.7 ZINCRBY(zincrby)
有序集合中对指定成员的分数加上增量 increment
Redis Zincrby 命令对有序集合中指定成员的分数加上增量 increment
可以通过传递一个负数值 increment ,让分数减去相应的值,比如 ZINCRBY key -5 member ,就是让 member 的 score 值减去 5 。
当 key 不存在,或分数不是 key 的成员时, ZINCRBY key increment member 等同于 ZADD key increment member 。
当 key 不是有序集类型时,返回一个错误。
分数值可以是整数值或双精度浮点数。
语法
127.0.0.1:6379> ZINCRBY key increment member
可以版本:>= 1.2.0
返回值:member 成员的新分数值,以字符串形式表示。
案例
127.0.0.1:6379> zrange myzset 0 -1 withscores #查看zset集合数据 1) "xiaoming" 2) "57" 3) "laoli" 4) "75" 5) "xiaowng" 6) "89" 7) "j3_liuliang" 8) "99" 127.0.0.1:6379> zincrby myzset 30 xiaoming #给倒数第一的分数加 30 "87" 127.0.0.1:6379> zrange myzset 0 -1 withscores #查看zset集合数据 1) "laoli" 2) "75" 3) "xiaoming" 4) "87" 5) "xiaowng" 6) "89" 7) "j3_liuliang" 8) "99" 127.0.0.1:6379> zincrby myzset -11 j3_liuliang #给第一得分数减 11 "88" 127.0.0.1:6379> zrange myzset 0 -1 withscores #查看zset集合数据 1) "laoli" 2) "75" 3) "xiaoming" 4) "87" 5) "j3_liuliang" 6) "88" 7) "xiaowng" 8) "89" 127.0.0.1:6379>
1.8 ZINTERSTORE(zinterstore)
计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中
计算给定的numkeys个有序集合的交集,并且把结果放到destination中。 在给定要计算的key和其它参数之前,必须先给定key个数(numberkeys)。
默认情况下,结果中一个元素的分数是有序集合中该元素分数之和,前提是该元素在这些有序集合中都存在。因为交集要求其成员必须是给定的每个有序集合中的成员,结果集中的每个元素的分数和输入的有序集合个数相等。
对于WEIGHTS和AGGREGATE参数的描述,参见命令ZUNIONSTORE。
如果destination存在,就把它覆盖。
语法
127.0.0.1:6379> ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
可以版本:>= 2.0.0
返回值:保存到目标结果集的的成员数量。
案例
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myzset01 18 j3_liuliang 25 xiaoming #设置集合数据 (integer) 2 127.0.0.1:6379> zadd myzset02 18 j3_liuliang 25 xiaomwang 23 laoli (integer) 3 127.0.0.1:6379> zinterstore myzset03 2 myzset01 myzset02 #求交集,将结果放入指定集合中 (integer) 1 127.0.0.1:6379> zrange myzset03 0 -1 withscores #查看结果集合数据 1) "j3_liuliang" 2) "36" 127.0.0.1:6379>
1.9 ZLEXCOUNT(zlexcount)
在有序集合中计算指定字典区间内成员数量
Redis Zlexcount 命令在计算有序集合中指定字典区间内成员数量。
语法
127.0.0.1:6379> ZLEXCOUNT KEY MIN MAX
key:有序集合键名称
min:在有序集合中分数排名较小的成员
max:在有序集合中分数排名较大的成员
提示:
成员名称前需要加 [ 符号作为开头, [ 符号与成员之间不能有空格
可以使用 - 和 + 表示得分最小值和最大值
min 和 max 不能反, max 放前面 min放后面会导致返回结果为0
计算成员之间的成员数量时,参数 min 和 max 的位置也计算在内。
min 和 max 参数的含义与 zrangebylex 命令中所描述的相同
可以版本:>= 2.8.9
返回值:有序集合中成员名称 min 和 max 之间的成员数量; Integer类型。
案例
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myzset01 0 a 1 b 2 c 3 d 4 e 5 f #设置有序集合数据 (integer) 6 127.0.0.1:6379> zadd myzset01 6 g 7 h 8 i (integer) 3 127.0.0.1:6379> zlexcount myzset01 - + #记录最小值和最大值之间得数据个数 (integer) 9 127.0.0.1:6379> zlexcount myzset01 [c [f #记录指定区间数据个数 (integer) 4 127.0.0.1:6379>
1.10 ZPOPMAX(zpopmax)
删除并返回有序集合key中的最多count个具有最高得分的成员。
如未指定,count的默认值为1。指定一个大于有序集合的基数的count不会产生错误。 当返回多个元素时候,得分最高的元素将是第一个元素,然后是分数较低的元素。
语法
127.0.0.1:6379> ZPOPMAX key [count]
可以版本:>=5.0.0
返回值:弹出的元素和分数列表。
案例
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myset 98 j3_liuliang 78 xiaowang 66 laoli 23 laozhang #添加数据 (integer) 4 127.0.0.1:6379> zpopmax myset 2 #弹出两个分数最大得成员 1) "j3_liuliang" 2) "98" 3) "xiaowang" 4) "78" 127.0.0.1:6379> zrange myset 0 -1 withscores #查看数据 1) "laozhang" 2) "23" 3) "laoli" 4) "66" 127.0.0.1:6379>
1.11 ZPOPMIN(zpopmin)
删除并返回有序集合key中的最多count个具有最低得分的成员。
如未指定,count的默认值为1。指定一个大于有序集合的基数的count不会产生错误。 当返回多个元素时候,得分最低的元素将是第一个元素,然后是分数较高的元素。
语法
127.0.0.1:6379> ZPOPMIN key [count]
可以版本:>=5.0.0
返回值:弹出的元素和分数列表。
案例
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myset 98 j3_liuliang 78 xiaowang 66 laoli 23 laozhang #添加数据 (integer) 4 127.0.0.1:6379> zpopmin myset 2 #弹出两个分数最小得成员 1) "laozhang" 2) "23" 3) "laoli" 4) "66" 127.0.0.1:6379> zrange myset 0 -1 withscores #查看数据 1) "xiaowang" 2) "78" 3) "j3_liuliang" 4) "98" 127.0.0.1:6379>
1.12 ZRANGEBYLEX(zrangebylex)
移除有序集合中给定的字典区间的所有成员
ZRANGEBYLEX 返回指定成员区间内的成员,按成员字典正序排序, 分数必须相同。
在某些业务场景中,需要对一个字符串数组按名称的字典顺序进行排序时,可以使用Redis中SortSet这种数据结构来处理。
语法
127.0.0.1:6379> ZRANGEBYLEX key min max [LIMIT offset count]
MIN:字典中排序位置较小的成员,必须以"[“开头,或者以”(“开头,可使用”-"代替
MAX:字典中排序位置较大的成员,必须以"[“开头,或者以”(“开头,可使用”+"代替
LIMIT:返回结果是否分页,指令中包含LIMIT后offset、count必须输入
OFFSET:返回结果起始位置
COUNT:返回结果数量
提示:
分数必须相同! 如果有序集合中的成员分数有不一致的,返回的结果就不准。
成员字符串作为二进制数组的字节数进行比较。
默认是以ASCII字符集的顺序进行排列。如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。
默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。”[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “min” 和 “max” 。
“max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。返回成员结果集不会包含 “max” 和 “min” 成员。
可以使用 “-“ 和 “+” 表示得分最小值和最大值
“min” 和 “max” 不能反, “max” 放前面 “min”放后面会导致返回结果为空
与ZRANGEBYLEX获取顺序相反的指令是ZREVRANGEBYLEX。
源码中采用C语言中memcmp()函数, 从字符的第0位到最后一位进行排序,如果前面部分相同,那么较长的字符串比较短的字符串排序靠后。
可以版本:>= 2.8.9
返回值:指定成员范围的元素列表。
案例
不要在分数不一致的SortSet集合中去使用 ZRANGEBYLEX 指令,因为获取的结果并不准确。
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myzset 1 sdf 1 sdf 1 dfgdf 1 sdf 1 yhjk 1 yj 1 gh #添加数据 (integer) 5 127.0.0.1:6379> zadd myzset 1 sde 1 fgnfg (integer) 2 127.0.0.1:6379> zrange myzset 0 -1 #查看数据 1) "dfgdf" 2) "fgnfg" 3) "gh" 4) "sde" 5) "sdf" 6) "yhjk" 7) "yj" 127.0.0.1:6379> zrangebylex myzset - + #查看范围内得所有数据 1) "dfgdf" 2) "fgnfg" 3) "gh" 4) "sde" 5) "sdf" 6) "yhjk" 7) "yj" 127.0.0.1:6379> zrangebylex myzset [gh [yj #查看范围内得所有数据 1) "gh" 2) "sde" 3) "sdf" 4) "yhjk" 5) "yj" 127.0.0.1:6379> zrange myzset 0 -1 #查看数据 1) "dfgdf" 2) "fgnfg" 3) "gh" 4) "sde" 5) "sdf" 6) "yhjk" 7) "yj" 127.0.0.1:6379>
1.13 ZRANGEBYSCORE(zrangebyscore)
返回有序集中指定分数区间内的成员,分数从高到低排序
语法
127.0.0.1:6379> ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
具有相同分数的元素按字典序排列(这个根据redis对有序集合实现的情况而定,并不需要进一步计算)。
可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。
可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。
区间及无限
min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。
默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。
举个例子:
ZRANGEBYSCORE zset (1 5 返回所有符合条件1 < score <= 5的成员; ZRANGEBYSCORE zset (5 (10 返回所有符合条件5 < score < 10 的成员。
可以版本:>=1.0.5
返回值:指定分数范围的元素列表(也可以返回他们的分数)。
案例
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myzset 1 one 2 two 3 three #添加数据 (integer) 3 127.0.0.1:6379> zrangebyscore myzset -inf +inf #获取所有从最小到最大范围内数据 1) "one" 2) "two" 3) "three" 127.0.0.1:6379> zrangebyscore myzset 1 (2 #获取 1<= x <2 得数据 1) "one" 127.0.0.1:6379> zrangebyscore myzset 2 3 #获取 2= x <=3 得数据 1) "two" 2) "three" 127.0.0.1:6379>
1.14 ZREMRANGEBYLEX(zremrangebylex)
移除有序集合中给定的字典区间的所有成员
ZREMRANGEBYLEX 删除名称按字典由低到高排序成员之间所有成员。
不要在成员分数不同的有序集合中使用此命令, 因为它是基于分数一致的有序集合设计的,如果使用,会导致删除的结果不正确。
待删除的有序集合中,分数最好相同,否则删除结果会不正常。
语法
127.0.0.1:6379> ZREMRANGEBYLEX key min max
key:有序集合键名称
min:字典中排序位置较小的成员,必须以"[“开头,或者以”(“开头,可使用”-"代替
max:字典中排序位置较大的成员,必须以"[“开头,或者以”(“开头,可使用”+"代替
提示:
有序集合中分数必须相同! 如果有序集合中的成员分数有不一致的,结果就不准。
成员顺序是按成员字符串作为二进制数组的字节数进行比较。
默认是以ASCII字符集的顺序进行排列。如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。
源码中采用C语言中memcmp()函数, 从字符的第0位到最后一位进行排序,如果前面部分相同,那么较长的字符串比较短的字符串排序靠后。
默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。”[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “max”和 “min”
“max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。返回成员结果集不会包含 “max” 和 “min” 成员。
可以使用 “-“ 和 “+” 表示得分最小值和最大值
“max”和 “min” 不能反, “max” 放后面 “min”放前面会删除不了元素
可以版本:>= 2.8.9
返回值:被成功移除的成员的数量,不包括被忽略的成员。
案例
27.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd myzset 0 a 0 b 0 c 0 d 0 e 0 dsfg 0 sdg #添加数据 (integer) 7 127.0.0.1:6379> zadd myzset 0 dfg 0 dfs (integer) 2 127.0.0.1:6379> zrange myzset 0 -1 #查看元素,不带分数 1) "a" 2) "b" 3) "c" 4) "d" 5) "dfg" 6) "dfs" 7) "dsfg" 8) "e" 9) "sdg" 127.0.0.1:6379> zremrangebylex myzset [a [c #移除指定区间数据 (integer) 3 127.0.0.1:6379> zrangebylex myzset - + #查看数据 1) "d" 2) "dfg" 3) "dfs" 4) "dsfg" 5) "e" 6) "sdg" 127.0.0.1:6379> zremrangebylex myzset [e (sdg #移除指定区间数据 (integer) 1 127.0.0.1:6379> zrangebylex myzset - + #查看数据 1) "d" 2) "dfg" 3) "dfs" 4) "dsfg" 5) "sdg" 127.0.0.1:6379>
1.15 ZREMRANGEBYRANK(zremrangebyrank)
移除有序集合中给定的排名区间的所有成员
移除有序集key中,指定排名(rank)区间内的所有成员。下标参数start和stop都以0为底,0处是分数最小的那个元素。这些索引也可是负数,表示位移从最高分处开始数。例如,-1是分数最高的元素,-2是分数第二高的,依次类推。
语法
127.0.0.1:6379> ZREMRANGEBYRANK key start stop
可以版本:>= 2.0.0
返回值:被移除成员的数量。
案例
127.0.0.1:6379> flushall OK 127.0.0.1:6379> zadd chengji 99 j3_liuliang 85 xiaoming 56 laowang #设置数据 (integer) 3 127.0.0.1:6379> zrange chengji 0 -1 withscores #查看数据 1) "laowang" 2) "56" 3) "xiaoming" 4) "85" 5) "j3_liuliang" 6) "99" 127.0.0.1:6379> zremrangebyrank chengji 0 1 #移除指定区间数据 (integer) 2 127.0.0.1:6379> zrange chengji 0 -1 withscores #查看数据 1) "j3_liuliang" 2) "99" 127.0.0.1:6379>