redis基本数据类型(zset有序集合)
- zset有序集合
-
- 存储类型
- 与list和set对比
- 常用操作命令
-
- zadd:添加成员到指定key的有序集合
- zcard:获取有序集合元素的数量
- zcount:获取指定分数范围的元素个数
- zincrby:给指定元素的score值加增量
- zinterstore
- zlexcount:获取有序集合中指定成员之间的成员数量
- zpopmax:获取有序集合中几个最高分的成员后删除
- zpopmin:获取有序集合中几个最低分的成员后删除
- zrange:获取给定范围内的元素
- ZRANGEBYLEX key min max [LIMIT offset count]
- ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
- zrank:获取有序集key中成员member的排名
- zrem:移除有序集合中指定的元素
- ZREMRANGEBYLEX key min max
- zremrangebyrank:移除有序集中指定排名区间的成员
- zremrangebyscore:移除有序集中指定分数间的成员
- zrevrange:获取指定范围的元素列表(可选是否含有分数)
- ZREVRANGEBYLEX key max min [LIMIT offset count]
- ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
- zrevrank:获取有序集key中成员member的排名
- zscore:获取有序集key中成员member的score值
- ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [SUM|MIN|MAX]
zset有序集合
存储类型
存储有序的元素。每个元素有个score,按照score从小到大排名。score相同时,按照key的ASCII码排序
与list和set对比
数据结构 | 是否允许重复元素 | 是否有序 | 有序实现方式 |
---|---|---|---|
list列表 | 是 | 是 | 索引下标 |
set集合 | 否 | 否 | 无 |
zset有序集合 | 否 | 是 | 分值score |
常用操作命令
zadd:添加成员到指定key的有序集合
-
命令
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
-
说明
将所有指定成员添加到键为
key
有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)对。 如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。如果
key
不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,就像原来存在一个空的有序集合一样。如果key
存在,但是类型不是有序集合,将会返回一个错误应答。分数值是一个双精度的浮点型数字字符串。
+inf
和-inf
都是有效值。 -
参数(option)(>=Redis 3.0.2)
ZADD 命令在
key
后面分数/成员(score/member)对前面支持一些参数,他们是:- XX: 仅仅更新存在的成员,不添加新成员。
- NX: 不更新存在的成员。只添加新成员。
- CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,
ZADD
返回值只计算新添加成员的数量。 - INCR: 当
ZADD
指定这个选项时,成员的操作就等同ZINCRBY
命令,对成员的分数进行递增操作。
-
分数可以精确的表示的整数的范围
Redis 有序集合的分数使用双精度64位浮点数。我们支持所有的架构,这表示为一个IEEE 754 floating point number,它能包括的整数范围是
-(2^53)
到+(2^53)
。或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。 -
sorted set 101
有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。 分数可以通过
ZADD
命令进行更新或者也可以通过ZINCRBY
命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。获取一个成员当前的分数可以使用
ZSCORE
命令,也可以用它来验证成员是否存在。 -
相同分数的成员
有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。当多个成员有相同的分数时,他们将是有序的字典(ordered lexicographically)(仍由分数作为第一排序条件,然后,相同分数的成员按照字典规则相对排序)。
字典顺序排序用的是二进制,它比较的是字符串的字节数组。
如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用
ZRANGEBYLEX
命令(注:范围查询分数可以使用ZRANGEBYSCORE
命令)。 -
返回值
- 添加到有序集合的成员数量,不包括已经存在更新分数的成员。
如果指定
INCR
参数, 返回将会变成bulk-string-reply :- 成员的新分数(双精度的浮点型数字)字符串。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 1 "uno" (integer) 1 redis> ZADD myzset 2 "two" 3 "three" (integer) 2 redis> ZRANGE myzset 0 -1 WITHSCORES 1) "one" 2) "1" 3) "uno" 4) "1" 5) "two" 6) "2" 7) "three" 8) "3" redis>
zcard:获取有序集合元素的数量
-
命令
ZCARD key
-
说明
返回key的有序集元素个数。
-
返回值
key存在的时候,返回有序集的元素个数,否则返回0。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZCARD myzset (integer) 2 redis>
zcount:获取指定分数范围的元素个数
-
命令
ZCOUNT key min max
-
说明
返回有序集key中,score值在min和max之间(默认包括score值等于min或max)的成员。 关于参数min和max的详细使用方法,请参考ZRANGEBYSCORE命令。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZCOUNT myzset -inf +inf (integer) 3 redis> ZCOUNT myzset (1 3 (integer) 2 redis>
zincrby:给指定元素的score值加增量
-
命令
ZINCRBY key increment member
-
说明
为有序集key的成员member的score值加上增量increment。如果key中不存在member,就在key中添加一个member,score是increment(就好像它之前的score是0.0)。如果key不存在,就创建一个只含有指定member成员的有序集合。
当key不是有序集类型时,返回一个错误。
score值必须是字符串表示的整数值或双精度浮点数,并且能接受double精度的浮点数。也有可能给一个负数来减少score的值。
-
返回值
member成员的新score值,以字符串形式表示。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZINCRBY myzset 2 "one" "3" redis> ZRANGE myzset 0 -1 WITHSCORES 1) "two" 2) "2" 3) "one" 4) "3" redis>
zinterstore
-
命令
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [SUM|MIN|MAX]
-
说明
计算给定的numkeys个有序集合的交集,并且把结果放到destination中。 在给定要计算的key和其它参数之前,必须先给定key个数(numberkeys)。
默认情况下,结果中一个元素的分数是有序集合中该元素分数之和,前提是该元素在这些有序集合中都存在。因为交集要求其成员必须是给定的每个有序集合中的成员,结果集中的每个元素的分数和输入的有序集合个数相等。
对于WEIGHTS和AGGREGATE参数的描述,参见命令ZUNIONSTORE。
如果destination存在,就把它覆盖。
-
返回值
结果有序集合destination中元素个数。
-
例子
ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3
结果放进out有序集合“one”的score = zset1 中“one”的score(1) * 2 + zset2 中“one”的score(1) * 3 = 5
“two”的score = zset1 中“two”的score(2) * 2 + zset2 中“two”的score(2) * 3 = 10
redis> ZADD zset1 1 "one" (integer) 1 redis> ZADD zset1 2 "two" (integer) 1 redis> ZADD zset2 1 "one" (integer) 1 redis> ZADD zset2 2 "two" (integer) 1 redis> ZADD zset2 3 "three" (integer) 1 redis> ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 (integer) 2 redis> ZRANGE out 0 -1 WITHSCORES 1) "one" 2) "5" 3) "two" 4) "10" redis>
zlexcount:获取有序集合中指定成员之间的成员数量
-
命令
ZLEXCOUNT key min max
-
说明
指令 是否必须 说明 zlexcount 是 指令 key 是 有序集合键名称 min 是 在有序集合中分数排名较小的成员 max 是 在有序集合中分数排名较大的成员 提示:
- 成员名称前需要加
[
符号作为开头,[
符号与成员之间不能有空格 - 可以使用
-
和+
表示得分最小值和最大值 min
和max
不能反,max
放前面min
放后面会导致返回结果为0- 计算成员之间的成员数量时,参数
min
和max
的位置也计算在内。 min
和max
参数的含义与zrangebylex
命令中所描述的相同
- 成员名称前需要加
-
返回值
有序集合中成员名称 min 和 max 之间的成员数量; Integer类型。
-
例子
-
计算成员之间成员数量
redis> ZADD myzset 0 a 0 b 0 c 0 d 0 e (integer) 5 redis> ZADD myzset 0 f 0 g (integer) 2 redis> ZLEXCOUNT myzset - + (integer) 7 redis> ZLEXCOUNT myzset [b [f (integer) 5 redis>
-
计算某个成员之前或者之后的成员数量
-
表示得分最小值的成员+
表示得分最大值的成员redis> ZADD myzset 1 a 2 b 3 c 4 d 5 e 6 f 7 g (integer) 7 redis> zrange myzset 0 -1 1) "a" 2) "b" 3) "c" 4) "d" 5) "e" 6) "f" 7) "g" redis> ZLEXCOUNT myzset - + (integer) 7 redis> ZLEXCOUNT myzset [c + (integer) 5 redis> ZLEXCOUNT myzset - [c (integer) 3 redis>
-
分数值位置的重要性
redis> del myzset (integer) 1 redis> ZADD myzset 1 a 2 b 3 c 4 d 5 e 6 f 7 g (integer) 7 redis> zrange myzset 0 -1 1) "a" 2) "b" 3) "c" 4) "d" 5) "e" 6) "f" 7) "g" redis> ZLEXCOUNT myzset [c [f (integer) 4 redis> ZLEXCOUNT myzset [f [c (integer) 0 redis>
-
zpopmax:获取有序集合中几个最高分的成员后删除
-
命令
ZPOPMAX key [count]
-
说明
删除并返回有序集合
key
中的最多count
个具有最高得分的成员。如未指定,
count
的默认值为1。指定一个大于有序集合的基数的count
不会产生错误。 当返回多个元素时候,得分最高的元素将是第一个元素,然后是分数较低的元素。 -
返回值
弹出的元素和分数列表。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZPOPMAX myzset 1) "3" 2) "three" redis>
zpopmin:获取有序集合中几个最低分的成员后删除
-
命令
ZPOPMIN key [count]
-
说明
删除并返回有序集合
key
中的最多count
个具有最低得分的成员。如未指定,
count
的默认值为1。指定一个大于有序集合的基数的count
不会产生错误。 当返回多个元素时候,得分最低的元素将是第一个元素,然后是分数较高的元素。 -
返回值
弹出的元素和分数列表。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZPOPMIN myzset 1) "1" 2) "one" redis>
zrange:获取给定范围内的元素
-
命令
ZRANGE key start stop [WITHSCORES]
-
说明
返回存储在有序集合
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
。 客户端类库可以自由地返回更合适的数据类型(建议:具有值和得分的数组或记录)。 -
例子
> ZADD myzset 1 "one" 1 > ZADD myzset 2 "two" 1 > ZADD myzset 3 "three" 1 > ZRANGE myzset 0 -1 one two three > ZRANGE myzset 2 3 three > ZRANGE myzset -2 -1 two three > ZRANGE myzset -2 -1 WITHSCORES two 2 three 3
ZRANGEBYLEX key min max [LIMIT offset count]
-
简介
ZRANGEBYLEX 返回指定成员区间内的成员,按成员字典正序排序, 分数必须相同。 在某些业务场景中,需要对一个字符串数组按名称的字典顺序进行排序时,可以使用Redis中SortSet这种数据结构来处理。
-
说明
指令 是否必须 说明 ZRANGEBYLEX 是 指令 key 是 有序集合键名称 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位到最后一位进行排序,如果前面部分相同,那么较长的字符串比较短的字符串排序靠后。
-
返回值
指定成员范围的元素列表。
-
例子
不要在分数不一致的SortSet集合中去使用 ZRANGEBYLEX 指令,因为获取的结果并不准确。
-
获取所有值
可以使用 “-“ 和 “+” 表示得分最小值和最大值
redis> zadd zset 0 a 0 aa 0 abc 0 apple 0 b 0 c 0 d 0 d1 0 dd 0 dobble 0 z 0 z1 (integer) 12 redis> ZRANGEBYLEX zset - + 1) "a" 2) "aa" 3) "abc" 4) "apple" 5) "b" 6) "c" 7) "d" 8) "d1" 9) "dd" 10) "dobble" 11) "z" 12) "z1"
-
获取分页数据
redis> ZRANGEBYLEX zset - + LIMIT 0 3 1) "a" 2) "aa" 3) "abc" redis> ZRANGEBYLEX zset - + LIMIT 3 3 1) "apple" 2) "b" 3) "c"
-
获取成员之间的元素
默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。
“[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “min” 和 “max” 。“min” 和 “max” 不能反, “max” 放前面 “min”放后面会导致返回结果为空
redis> ZRANGEBYLEX zset [aa [c 1) "aa" 2) "abc" 3) "apple" 4) "b" 5) "c" redis> ZRANGEBYLEX zset [c [aa (empty list or set)
-
使用 “(“ 小于号获取成员之间的元素
“max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。
返回成员结果集不会包含 “max” 和 “min” 成员。redis> ZRANGEBYLEX zset [aa (c 1) "aa" 2) "abc" 3) "apple" 4) "b"
-
ASCII码的影响
成员字符串作为二进制数组的字节数进行比较。
默认是以ASCII字符集的顺序进行排列。
如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。redis> zadd zset 0 aBc (integer) 1 redis> ZRANGEBYLEX zset - + 1) "a" 2) "aBc" 3) "aa" 4) "abc" 5) "apple" 6) "b" 7) "c" 8) "d" 9) "d1" 10) "dd" 11) "dobble" 12) "z" 13) "z1" redis> ZRANGEBYLEX zset - + LIMIT 0 3 1) "a" 2) "aBc" 3) "aa"
-
-
使用场景
-
电话号码排序
我们可以将电话号码存储到SortSet中,然后根据需要来获取号段:
redis> zadd phone 0 13100111100 0 13110114300 0 13132110901 (integer) 3 redis> zadd phone 0 13200111100 0 13210414300 0 13252110901 (integer) 3 redis> zadd phone 0 13300111100 0 13310414300 0 13352110901 (integer) 3
获取所有号码:
redis> ZRANGEBYLEX phone - + 1) "13100111100" 2) "13110114300" 3) "13132110901" 4) "13200111100" 5) "13210414300" 6) "13252110901" 7) "13300111100" 8) "13310414300" 9) "13352110901"
获取132号段:
redis> ZRANGEBYLEX phone [132 (133 1) "13200111100" 2) "13210414300" 3) "13252110901"
获取132、133号段:
redis> ZRANGEBYLEX phone [132 (134 1) "13200111100" 2) "13210414300" 3) "13252110901" 4) "13300111100" 5) "13310414300" 6) "13352110901"
-
xing
-
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
-
说明
如果M是常量(比如,用limit总是请求前10个元素),你可以认为是O(log(N))。
返回key的有序集合中的分数在min和max之间的所有元素(包括分数等于max或者min的元素)。元素被认为是从低分到高分排序的。
具有相同分数的元素按字典序排列(这个根据redis对有序集合实现的情况而定,并不需要进一步计算)。
可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。
可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。
##区间及无限
min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。
默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。
-
返回值
指定分数范围的元素列表(也可以返回他们的分数)。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZRANGEBYSCORE myzset -inf +inf 1) "one" 2) "two" 3) "three" redis> ZRANGEBYSCORE myzset 1 2 1) "one" 2) "two" redis> ZRANGEBYSCORE myzset (1 2 1) "two" redis> ZRANGEBYSCORE myzset (1 (2 (empty list or set) redis>
zrank:获取有序集key中成员member的排名
-
命令
ZRANK key member
-
说明
返回有序集key中成员member的排名。其中有序集成员按score值递增(从小到大)顺序排列。排名以0为底,也就是说,score值最小的成员排名为0。
使用ZREVRANK命令可以获得成员按score值递减(从大到小)排列的排名。
-
返回值
- 如果member是有序集key的成员,返回member的排名。
- 如果member不是有序集key的成员,返回
nil
。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZRANK myzset "three" (integer) 2 redis> ZRANK myzset "four" (nil) redis>
zrem:移除有序集合中指定的元素
-
命令
ZREM key member [member ...]
-
说明
当key存在,但是其不是有序集合类型,就返回一个错误。
-
返回值
返回的是从有序集合中删除的成员个数,不包括不存在的成员。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZREM myzset "two" (integer) 1 redis> ZRANGE myzset 0 -1 WITHSCORES 1) "one" 2) "1" 3) "three" 4) "3" redis>
ZREMRANGEBYLEX key min max
-
简介
ZREMRANGEBYLEX 删除名称按字典由低到高排序成员之间所有成员。
不要在成员分数不同的有序集合中使用此命令, 因为它是基于分数一致的有序集合设计的,如果使用,会导致删除的结果不正确。
待删除的有序集合中,分数最好相同,否则删除结果会不正常。 -
说明
指令 是否必须 说明 ZREMRANGEBYLEX 是 指令 key 是 有序集合键名称 min 是 字典中排序位置较小的成员,必须以"[“开头,或者以”(“开头,可使用”-"代替 max 是 字典中排序位置较大的成员,必须以"[“开头,或者以”(“开头,可使用”+"代替 提示:
- 有序集合中分数必须相同! 如果有序集合中的成员分数有不一致的,结果就不准。
- 成员顺序是按成员字符串作为二进制数组的字节数进行比较。
- 默认是以ASCII字符集的顺序进行排列。如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。
- 源码中采用C语言中
memcmp()
函数, 从字符的第0位到最后一位进行排序,如果前面部分相同,那么较长的字符串比较短的字符串排序靠后。 - 默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。”[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “max”和 “min”
- “max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。返回成员结果集不会包含 “max” 和 “min” 成员。
- 可以使用 “-“ 和 “+” 表示得分最小值和最大值
- “max”和 “min” 不能反, “max” 放后面 “min”放前面会删除不了元素
-
返回值
删除元素的个数。
-
例子
不要在分数不一致的SortSet集合中去使用 ZREMRANGEBYLEX 指令,因为获取的结果并不准确。
-
删除所有元素
可以使用 “-“ 和 “+” 表示最小值和最大值
redis> zadd zset 0 a 0 aa 0 abc 0 apple 0 b 0 c 0 d 0 d1 0 dd 0 dobble 0 z 0 z1 (integer) 12 redis> ZRANGEBYLEX zset + - 1) "a" 2) "aa" 3) "abc" 4) "apple" 5) "b" 6) "c" 7) "d" 8) "d1" 9) "dd" 10) "dobble" 11) "z" 12) "z1" redis> ZREMRANGEBYLEX zset - + (integer) 7 redis> ZRANGEBYLEX zset - + (empty list or set)
-
按名称删除某个元素
下面是删除d1这个元素
redis> zadd zset 0 a 0 aa 0 abc 0 apple 0 b 0 c 0 d 0 d1 0 dd 0 dobble 0 z 0 z1 (integer) 12 redis> ZRANGEBYLEX zset - + 1) "a" 2) "aa" 3) "abc" 4) "apple" 5) "b" 6) "c" 7) "d" 8) "d1" 9) "dd" 10) "dobble" 11) "z" 12) "z1" redis> ZREMRANGEBYLEX zset [d1 (dd (integer) 1 redis> ZRANGEBYLEX zset - + 1) "a" 2) "aa" 3) "abc" 4) "apple" 5) "b" 6) "c" 7) "d" 8) "dd" 9) "dobble" 10) "z" 11) "z1"
-
按名称删除成员之间的元素,包含”max” 和 “min”成员
默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。
“[” 符号与成员之间不能有空格, 删除成员包含参数 “min” 和 “max” 。redis> ZRANGEBYLEX zset - + 1) "a" 2) "aa" 3) "abc" 4) "apple" 5) "b" 6) "c" 7) "d" 8) "dd" 9) "dobble" 10) "z" 11) "z1" redis> ZREMRANGEBYLEX zset [a [apple (integer) 4 redis> ZRANGEBYLEX zset - + 1) "b" 2) "c" 3) "d" 4) "dd" 5) "dobble" 6) "z" 7) "z1"
“min” 和 “max” 不能反, “min” 放前面 “max”放后面会导致无法删除元素
redis> ZREMRANGEBYLEX zset [dobble [d (integer) 0
-
按名称删除成员之间的元素,不包含”max” 和 “min”成员
“max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。
删除成员不会包含 “max” 和 “min” 成员。redis> ZRANGEBYLEX zset - + 1) "b" 2) "c" 3) "d" 4) "dd" 5) "dobble" 6) "z" 7) "z1" redis> ZREMRANGEBYLEX zset (d (dobble (integer) 1 redis> ZRANGEBYLEX zset - + 1) "b" 2) "c" 3) "d" 4) "dobble" 5) "z" 6) "z1"
-
zremrangebyrank:移除有序集中指定排名区间的成员
-
命令
ZREMRANGEBYRANK key start stop
-
说明
移除有序集key中,指定排名(rank)区间内的所有成员。下标参数start和stop都以0为底,0处是分数最小的那个元素。这些索引也可是负数,表示位移从最高分处开始数。例如,-1是分数最高的元素,-2是分数第二高的,依次类推。
-
返回值
被移除成员的数量。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZREMRANGEBYRANK myzset 0 1 (integer) 2 redis> ZRANGE myzset 0 -1 WITHSCORES 1) "three" 2) "3" redis>
zremrangebyscore:移除有序集中指定分数间的成员
-
命令
ZREMRANGEBYRANK key start stop
-
说明
移除有序集key中,所有score值介于min和max之间(包括等于min或max)的成员。 自版本2.1.6开始,score值等于min或max的成员也可以不包括在内,语法请参见ZRANGEBYSCORE命令。
-
返回值
移除有序集key中,所有score值介于min和max之间(包括等于min或max)的成员。 自版本2.1.6开始,score值等于min或max的成员也可以不包括在内,语法请参见ZRANGEBYSCORE命令。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZREMRANGEBYSCORE myzset -inf (2 (integer) 1 redis> ZRANGE myzset 0 -1 WITHSCORES 1) "two" 2) "2" 3) "three" 4) "3" redis>
zrevrange:获取指定范围的元素列表(可选是否含有分数)
-
命令
ZREVRANGE key start stop [WITHSCORES]
-
说明
返回有序集key中,指定区间内的成员。其中成员的位置按score值递减(从大到小)来排列。具有相同score值的成员按字典序的反序排列。 除了成员按score值递减的次序排列这一点外,ZREVRANGE命令的其他方面和ZRANGE命令一样。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZREVRANGE myzset 0 -1 1) "three" 2) "two" 3) "one" redis> ZREVRANGE myzset 2 3 1) "one" redis> ZREVRANGE myzset -2 -1 1) "two" 2) "one" redis>
ZREVRANGEBYLEX key max min [LIMIT offset count]
-
简介
ZREVRANGEBYLEX 返回指定成员区间内的成员,按成员字典倒序排序, 分数必须相同。
在某些业务场景中,需要对一个字符串数组按名称的字典顺序进行倒序排列时,可以使用Redis中SortSet这种数据结构来处理。 -
说明
指令 是否必须 说明 ZREVRANGEBYLEX 是 指令 key 是 有序集合键名称 max 是 字典中排序位置较大的成员,必须以"[“开头,或者以”(“开头,可使用”+"代替 min 是 字典中排序位置较小的成员,必须以"[“开头,或者以”(“开头,可使用”-"代替 LIMIT 否 返回结果是否分页,指令中包含LIMIT后offset、count必须输入 offset 否 返回结果起始位置 count 否 返回结果数量 提示:
- 分数必须相同! 如果有序集合中的成员分数有不一致的,返回的结果就不准。
- 成员字符串作为二进制数组的字节数进行比较。
- 默认是以ASCII字符集的顺序进行排列。如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。
- 源码中采用C语言中
memcmp()
函数, 从字符的第0位到最后一位进行排序,如果前面部分相同,那么较长的字符串比较短的字符串排序靠前。 - 默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。”[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “max”和 “min”
- “max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。返回成员结果集不会包含 “max” 和 “min” 成员。
- 可以使用 “-“ 和 “+” 表示得分最小值和最大值
- “max”和 “min” 不能反, “max” 放后面 “min”放前面会导致返回结果为空
- 与ZREVRANGEBYLEX获取顺序相反的指令是ZREVRANGEBYLEX。
-
返回值
指定成员范围的元素列表。
-
例子
不要在分数不一致的SortSet集合中去使用 ZREVRANGEBYLEX 指令,因为获取的结果并不准确。
-
获取所有值
可以使用 “-“ 和 “+” 表示最小值和最大值
redis> zadd zset 0 a 0 aa 0 abc 0 apple 0 b 0 c 0 d 0 d1 0 dd 0 dobble 0 z 0 z1 (integer) 12 redis> ZREVRANGEBYLEX zset + - 1) "z1" 2) "z" 3) "dobble" 4) "dd" 5) "d1" 6) "d" 7) "c" 8) "b" 9) "apple" 10) "abc" 11) "aa" 12) "a"
-
获取分页数据
redis> ZREVRANGEBYLEX zset + - LIMIT 0 3 1) "z1" 2) "z" 3) "dobble" redis> ZREVRANGEBYLEX zset + - LIMIT 3 3 1) "dd" 2) "d1" 3) "d"
-
获取成员之间的元素
默认情况下, “max” 和 “min” 参数前必须加 “[” 符号作为开头。
“[” 符号与成员之间不能有空格, 返回成员结果集会包含参数 “min” 和 “max” 。“min” 和 “max” 不能反, “min” 放前面 “max”放后面会导致返回结果为空
redis> ZREVRANGEBYLEX zset [c [aa 1) "c" 2) "b" 3) "apple" 4) "abc" 5) "aa" redis> ZREVRANGEBYLEX zset [aa [c (empty list or set)
-
使用 “(“ 小于号获取成员之间的元素
“max” 和 “min” 参数前可以加 “(“ 符号作为开头表示小于, “(“ 符号与成员之间不能有空格。
返回成员结果集不会包含 “max” 和 “min” 成员。redis> ZREVRANGEBYLEX zset (c [aa 1) "b" 2) "apple" 3) "abc" 4) "aa"
-
ASCII码的影响
成员字符串作为二进制数组的字节数进行比较。
默认是以ASCII字符集的顺序进行排列。
如果成员字符串包含utf-8这类字符集的内容,就会影响返回结果,所以建议不要使用。redis> zadd zset 0 dB (integer) 1 redis> ZREVRANGEBYLEX zset + - 1) "z1" 2) "z" 3) "dobble" 4) "dd" 5) "dB" 6) "d1" 7) "d" 8) "c" 9) "b" 10) "apple" 11) "abc" 12) "aa" 13) "a" redis> ZREVRANGEBYLEX zset + - limit 0 3 1) "z1" 2) "z" 3) "dobble" redis> ZREVRANGEBYLEX zset + - limit 3 3 1) "dd" 2) "dB" 3) "d1"
-
-
使用场景
-
电话号码排序
我们可以将电话号码存储到SortSet中,然后根据需要来获取号段:
redis> zadd phone 0 13100111100 0 13110114300 0 13132110901 (integer) 3 redis> zadd phone 0 13200111100 0 13210414300 0 13252110901 (integer) 3 redis> zadd phone 0 13300111100 0 13310414300 0 13352110901 (integer) 3
从大到小获取所有号码:
redis> ZREVRANGEBYLEX phone + - 1) "13352110901" 2) "13310414300" 3) "13300111100" 4) "13252110901" 5) "13210414300" 6) "13200111100" 7) "13132110901" 8) "13110114300" 9) "13100111100"
获取132号段:
redis> ZREVRANGEBYLEX phone (133 [132 1) "13252110901" 2) "13210414300" 3) "13200111100"
获取132、133号段:
redis> ZREVRANGEBYLEX phone (134 [132 1) "13352110901" 2) "13310414300" 3) "13300111100" 4) "13252110901" 5) "13210414300" 6) "13200111100"
-
姓名排序
将名称存储到SortSet中:
redis> zadd names 0 Toumas 0 Jake 0 Bluetuo 0 Gaodeng 0 Aimini 0 Aidehua (integer) 6
获取所有人的名字倒序排列:
redis> ZREVRANGEBYLEX names + - 1) "Toumas" 2) "Jake" 3) "Gaodeng" 4) "Bluetuo" 5) "Aimini" 6) "Aidehua"
获取名字中大写字母A开头的所有人:
redis> ZREVRANGEBYLEX names (B [A 1) "Aimini" 2) "Aidehua"
获取名字中大写字母C到Z的所有人:
redis> ZREVRANGEBYLEX names [Z [C 1) "Toumas" 2) "Jake" 3) "Gaodeng"
-
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
-
简介
ZREVRANGEBYSCORE
返回有序集合中指定分数区间内的成员,分数由高到低排序。 -
说明
指令 是否必须 说明 ZREVRANGEBYSCORE 是 指令 key 是 有序集合键名称 max 是 最大分数值,可使用"+inf"代替 min 是 最小分数值,可使用"-inf"代替 WITHSCORES 否 将成员分数一并返回 LIMIT 否 返回结果是否分页,指令中包含LIMIT后offset、count必须输入 offset 否 返回结果起始位置 count 否 返回结果数量 提示:
"max"
和"min"
参数前可以加"("
符号作为开头表示小于,"("
符号与成员之间不能有空格- 可以使用
"+inf"
和"-inf"
表示得分最大值和最小值 "max"
和"min"
不能反,"max"
放后面"min"
放前面会导致返回结果为空- 计算成员之间的成员数量不加
"("
符号时,参数"min"
和"max"
的位置也计算在内。 - ZREVRANGEBYSCORE集合中按得分从高到底排序,所以
"max"
在前面,"min"
在后面, ZRANGEBYSCORE集合中按得分从底到高排序,所以"min"
在前面,"max"
在后面。
-
返回值
指定分数范围的元素列表。
-
例子
-
按分数倒序返回成员
"+inf"
或者"-inf"
来表示记录中最大值和最小值。"("
左括号来表示小于某个值。目前只支持小于操作的"("
左括号, 右括号(大于)目前还不能支持。redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZREVRANGEBYSCORE myzset +inf -inf 1) "three" 2) "two" 3) "one" redis> ZREVRANGEBYSCORE myzset 2 1 1) "two" 2) "one" redis> ZREVRANGEBYSCORE myzset 2 (1 1) "two" redis> ZREVRANGEBYSCORE myzset (2 (1 (empty list or set) redis>
-
按分数倒序返回成员以及分数
ZREVRANGEBYSCORE
指令中, 还可以使用WITHSCORES
关键字来要求返回成员列表以及分数。redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZREVRANGEBYSCORE myzset +inf -inf WITHSCORES 1) "three" 2) "3" 3) "two" 4) "2" 5) "three" 6) "1" redis> ZREVRANGEBYSCORE myzset 2 1 WITHSCORES 1) "two" 2) "2" 3) "one" 4) "1" redis> ZREVRANGEBYSCORE myzset 2 (1 1) "two" redis> ZREVRANGEBYSCORE myzset (2 (1 (empty list or set) redis>
-
分页返回数据
可以通过
LIMIT
对满足条件的成员列表进行分页。一般会配合"+inf"
或者"-inf"
来表示最大值和最小值。 下面的例子中就是使用分页参数返回数据的例子。redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZREVRANGEBYSCORE myzset +inf (2 WITHSCORES LIMIT 0 1 1) "three" 2) "3" redis> ZREVRANGEBYSCORE myzset +inf (2 WITHSCORES LIMIT 2 3 (empty list or set) redis>
-
-
应用
-
时事新闻
我们的网易新闻、腾讯新闻、一点资讯、虎嗅、快科技等新闻类应用场景中, 新闻会根据时间排列,形成一个队列, 在这些网站浏览新闻时, 每次刷新页面都能获取到最新的数据,当然还可以通过分页查看历史数据, 但每次刷新首页都将是一个以最新数据为基础进行分页。 这又区别于面前今日头条的下拉刷新机制,关于今日头条的下拉刷新机制我们下节讲,这一节先讲讲如何实现新闻资讯队列分页。
场景及需求:
根据数据类型分频道来展示资讯,比如时事新闻,根据时间排序,用户进入网站就获取到最新时事新闻,后台能实时向时事新闻频道增加新闻,且只要用户刷新就能看到最新的时事新闻,然后以最新新闻为基础进行分页展示。 我们根据时间添加5条新闻到news频道。
redis> zadd news 201610022301 '{"title" : "new1", "time": 201610022301}' (integer) 1 redis> zadd news 201610022302 '{"title" : "new2", "time": 201610022302}' (integer) 1 redis> zadd news 201610022303 '{"title" : "new3", "time": 201610022303}' (integer) 1 redis> zadd news 201610022304 '{"title" : "new4", "time": 201610022304}' (integer) 1 redis> zadd news 201610022305 '{"title" : "new5", "time": 201610022305}'
实际场景中new1、news2…等等都应该是一个json对象,包含新闻标题、时间、作者、类型、图片URL…等等信息。 然后当用户请求新闻时,我们会使用这个命令查询出最新几条记录:
redis> ZREVRANGEBYSCORE news +inf -inf LIMIT 0 2 1) "{\"title\" : \"new5\", \"time\": 201610022305}" 2) "{\"title\" : \"new4\", \"time\": 201610022304}"
上面的例子中,我们从news频道查询出来了2条最新记录。如果用户翻页,我们会使用最新记录中时间最大的记录做为参数进行分页。依次查询第二页,第三页。
redis> ZREVRANGEBYSCORE news 201610022305 -inf LIMIT 2 2 1) "{\"title\" : \"new3\", \"time\": 201610022303}" 2) "{\"title\" : \"new2\", \"time\": 201610022302}" redis> ZREVRANGEBYSCORE news 201610022305 -inf LIMIT 4 2 1) "{\"title\" : \"new1\", \"time\": 201610022301}" redis>
总结: 我这里没有使用当前时间作为最大值查询,是为了避免用户电脑时间不准确导致请求失败。比如刚装系统,或者BOIS电池没有电,不能存储系统当前时间,就会导致系统时间都是1970年1月1日,这样,去查询,是查询不到数据的,比如之前的太平洋电脑网,如果你将电脑系统时间改成1970年1月1日,再去访问,就无法获取新数据了。现在有不少网站有类似问题. 在这个业务场景中,如果某个编辑新发布一条新闻到时事新闻中,原来在翻页查看新闻的用户是不受影响的,只有用户刷新浏览器或者刷新首页,就会看到最新的数据了。
-
时事新闻下拉更新
上面时事新闻的例子能解决一部分业务场景的需求,但是如果遇到比较较真的产品经理,需要做成类似今日头条下拉刷新最新数据,上拉获取历史记录的功能,那么一个
ZREVRANGEBYSCORE
命令肯定是解决不了问题的。下面我讲讲我一些解决方案的思路。
首先,从队列的角度看需求,以201610022303这个时间为界限,下拉刷新如果获最新数据,就是这样:redis> ZREVRANGEBYSCORE news +inf 201610022303 LIMIT 0 2 1) "{\"title\" : \"new5\", \"time\": 201610022305}" 2) "{\"title\" : \"new4\", \"time\": 201610022304}"
然后,上拉刷新获取历史数据,分页查询,都没有问题:
redis> ZREVRANGEBYSCORE news 201610022303 -inf LIMIT 0 2 1) "{\"title\" : \"new3\", \"time\": 201610022303}" 2) "{\"title\" : \"new2\", \"time\": 201610022302}" redis> ZREVRANGEBYSCORE news 201610022303 -inf LIMIT 2 2 1) "{\"title\" : \"new1\", \"time\": 201610022301}" redis>
不过,你会发现,下拉刷新时,数据是从最大时间到最小时间排序,如果编辑新增一条数据,就会打乱我们队列的顺序
redis> zadd news 201610022306 '{"title" : "new6", "time": 201610022306}' (integer) 1 redis> ZREVRANGEBYSCORE news +inf 201610022303 LIMIT 2 2 1) "{\"title\" : \"new4\", \"time\": 201610022304}" 2) "{\"title\" : \"new3\", \"time\": 201610022303}" redis>
前一秒,查询第一页数据是news5和news4,我翻页的时候,结果变成了news4和news3,news4重复了。 虽然不会对上拉刷新查询历史数据有影响,但是作为一个实时性非常强的新闻应用,用户更关注的应该是最新的新闻的内容,也就是下拉刷新的功能,如果一个基本的排版都重复,用户的耐心恐怕不会给你更多机会。 想到这,感觉太可怕了!产品经理要是知道,一定会喷死我们的。当然,这不是最要命的问题,最要命的问题是如果用户要是回到第一页(非刷新),就会发现,当初的第一页已经不是刚刚看过的第一页了。 第一页多了一条news6的新闻!
redis> ZREVRANGEBYSCORE news +inf 201610022303 LIMIT 0 2 1) "{\"title\" : \"new6\", \"time\": 201610022306}" 2) "{\"title\" : \"new5\", \"time\": 201610022305}"
还有一个问题,就是如果用户前一天看到第二页,隔天登录,然后请求最新新闻,还会是第二页吗? 可以考虑以下解决思路:
首先,需要前端和后端配合,前端定义三个动作,首次登录,下拉刷新(获取最新数据),上拉刷新(获取历史数据),定义一个下拉刷新时间和一个上拉刷新时间, 如果是首次登录,先判断下拉刷新时间是否比今天凌晨时间小,如果小,证明已经隔天了,将下拉刷新时间设置成当天凌晨时间; 如果下拉刷新时间比今天凌晨时间大,说明用户看过今天新闻,就直接用下拉刷新时间请求新数据。 对于上拉刷新请求数据,可以在判断首次请求时,出现隔天后,将上拉刷新时间置为当天凌晨时间。这样在请求历史数据时,不至于丢失中间的数据。 当然,关键还是命令的使用,查询历史数据时,还可以使用ZREVRANGEBYSCORE
来获取数据,不过,获取最新数据,就可以使用ZRANGEBYSCORE
来取数据。redis> zadd news 201610030110 '{"title" : "new7", "time": 201610030110}' (integer) 1 redis> zadd news 201610030111 '{"title" : "new8", "time": 201610030111}' (integer) 1 redis> zadd news 201610030112 '{"title" : "new9", "time": 201610030112}' (integer) 1 redis> ZRANGEBYSCORE news 201610030000 +inf LIMIT 0 2 1) "{\"title\" : \"new7\", \"time\": 201610030110}" 2) "{\"title\" : \"new8\", \"time\": 201610030111}" redis> ZRANGEBYSCORE news 201610030000 +inf LIMIT 2 2 1) "{\"title\" : \"new9\", \"time\": 201610030112}"
总结: 时事新闻下拉更新这个例子中, 可以使用每次请求数据的最大时间戳和最小时间戳来作为下一次请求的输入,这里的时间戳的概念不限于时间,可以是数据库里的自增ID,然后在缓存中定义一个当天的ID,每当隔天出现,就取获取这个ID,然后通过这个ID作为当天凌晨的时间戳标记, 获取比这个ID大或者小的结果集来完成获取最新数据和历史数据的功能,这样就可以解决客户端时间不准确后获取不到数据的问题。
-
zrevrank:获取有序集key中成员member的排名
-
命令
ZREVRANK key member
-
说明
- 如果member是有序集key的成员,返回integer-reply:member的排名。
- 如果member不是有序集key的成员,返回bulk-string-reply:
nil
。
-
返回值
被移除成员的数量。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZADD myzset 2 "two" (integer) 1 redis> ZADD myzset 3 "three" (integer) 1 redis> ZREVRANK myzset "one" (integer) 2 redis> ZREVRANK myzset "four" (nil) redis>
zscore:获取有序集key中成员member的score值
-
命令
ZSCORE key member
-
说明
返回有序集key中,成员member的score值。
如果member元素不是有序集key的成员,或key不存在,返回nil。
-
返回值
member成员的score值(double型浮点数),以字符串形式表示。
-
例子
redis> ZADD myzset 1 "one" (integer) 1 redis> ZSCORE myzset "one" "1" redis>
ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight] [SUM|MIN|MAX]
-
说明
计算给定的numkeys个有序集合的并集,并且把结果放到destination中。在给定要计算的key和其它参数之前,必须先给定key个数(numberkeys)。 默认情况下,结果集中某个成员的score值是所有给定集下该成员score值之和。
使用WEIGHTS选项,你可以为每个给定的有序集指定一个乘法因子,意思就是,每个给定有序集的所有成员的score值在传递给聚合函数之前都要先乘以该因子。如果WEIGHTS没有给定,默认就是1。
使用AGGREGATE选项,你可以指定并集的结果集的聚合方式。默认使用的参数SUM,可以将所有集合中某个成员的score值之和作为结果集中该成员的score值。如果使用参数MIN或者MAX,结果集就是所有集合中元素最小或最大的元素。
如果key destination存在,就被覆盖。
-
返回值
结果有序集合destination中元素个数。
-
例子
redis> ZADD zset1 1 "one" (integer) 1 redis> ZADD zset1 2 "two" (integer) 1 redis> ZADD zset2 1 "one" (integer) 1 redis> ZADD zset2 2 "two" (integer) 1 redis> ZADD zset2 3 "three" (integer) 1 redis> ZUNIONSTORE out 2 zset1 zset2 WEIGHTS 2 3 (integer) 3 redis> ZRANGE out 0 -1 WITHSCORES 1) "one" 2) "5" 3) "three" 4) "9" 5) "two" 6) "10" redis>