2、Redis 的五大基本数据类型
注:这里说的数据类型是 Value 的数据类型,Key 的类型都是字符串类型;
Redis 中的五种基本数据类型:
- 字符串:String
- 列表:List
- 集合:Set
- 哈希表:Hash
- 有序集合:Zset
Redis中常用数据类型操作命令:http://redis.cn/commands.html
2.1、Redis 中对键(Key)的操作
命令 | 解释 |
---|---|
keys * | 查看当前库所有的key |
exists key | 判断某个key是否存在 |
type key | 查看你的key是什么类型 |
del key | 删除指定的key数据 |
unlink key | 与 del key 类似,del key 为同步删除,unlink key 为异步删除; 建议:删除 Redis 中的大 Key 时,使用 unlink key,否则使用 del key |
expire key 10 | 为指定的key设置有效期10秒 |
ttl key | 查看指定的key还有多少秒过期,-1:表示永不过期,-2:表示已过期 |
select dbindex | 切换数据库【0-15】,默认为0 |
dbsize | 查看当前数据库key的数量 |
flushdb | 清空当前库 |
flushall | 通杀全部库 |
2.2、Redis 中的字符串类型操作(String)
2.2.1、简介
String 是 Redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。
String 类型是二进制安全的。意味着 Redis的 string 可以包含任何数据。比如 jpg 图片或者序列化的对象。
String 类型是 Redis 最基本的数据类型,一个 Redis 中字符串 value 最多可以是 512M
2.2.2、常用命令
操作 | 作用 |
---|---|
set | 添加键值对 |
get | 获取 key 对应的值 |
apend | 将给定的 value 追加到原值的末尾。 |
strlen | 获取 key 对应的值的长度 |
setnx | 当 key 不存在时,设置 key 的值 |
incr | 将 key 中存储的值加 1,只能对数字值操作,如果为空,新增值为 1 |
decr | 将 key 中存储的值减 1,只能对数字值操作,如果为空,新增值为 -1 |
incrby | 将 key 中存储的数字值递增指定的步长,若 key 不存在,则相当于在原值为 0 的值上递增指定的步长。 |
decrby | 将 key 中存储的数字值递减指定的步长,若 key 不存在,则相当于在原值为 0 的值上递减指定的步长。 |
mset | 同时设置多个 key-value |
mget | 同时获取多个 key 的值 |
msetnx | 当多个 key 均不存在时,则设置成功 |
getrange | 类似 java 中的 substring |
setrange | 覆盖指定位置的值 |
setex | 设置键值,并设置过期时间 |
getset | 以旧换新,设置新值同时返回旧值 |
set 添加键值对
127.0.0.1:6379> set key value [EX seconds|PX milliseconds|EXAT timestamp|PXAT milliseconds-timestamp|KEEPTTL] [NX|XX] [GET]
NX:当数据库中 key 不存在时,可以将 key-value 添加到数据库
XX:当数据库中 key 存在时,可以将 key-value 添加数据库,与 NX 参数互斥
EX:key 的超时秒数
PX:key 的超时毫秒数,与 EX 互斥
value 中若包含空格、特殊字符,需用双引号包裹
get 获取值
127.0.0.1:6379> get <key>
apend 追加值
# 将给定的value追加到原值的末尾。
127.0.0.1:6379> append <key> <value>
strlen 获取值的长度
127.0.0.1:6379> strlen <key>
setnx 不存在时,设置 key 的值
# 成功返回 1,失败返回 0;
127.0.0.1:6379> setnx <key> <value>
incr 递增 1
# 将 key 中存储的值减 1,只能对数字值操作,如果为空,新增值为 1
127.0.0.1:6379> incr <key>
decr 递减 1
# 将 key 中存储的值减 1,只能对数字值操作,如果为空,新增值为 -1
127.0.0.1:6379> decr <key>
incrby/decrby 递增/递减 指定数字
# 将 key 中存储的数字值递增指定的步长,若key不存在,则相当于在原值为0的值上递增指定的步长。
127.0.0.1:6379> incrby <key> <步长>
127.0.0.1:6379> decrby <key> <步长>
mset 同时设置多个 key-value
127.0.0.1:6379> mset <key1> <value1> <key2> <value2>
mget 同时获取多个 key 的值
127.0.0.1:6379> mget <key1> <key2>
msetnx 当多个 key 均不存在时,则设置成功
# Redis 操作均为原子性操作,要么都成功,要么都失败
127.0.0.1:6379> msetnx <key1> <value1> <key2> <value2>
getrange 类似 Java 中的 substring
# 获取 [start,end] 返回为的字符串,下标从 0 开始
127.0.0.1:6379> getrange key start end
setrange 覆盖指定位置的值
127.0.0.1:6379> setrange <key> <起始位置> <value>
示例:
127.0.0.1:6379> set k1 helloworld
OK
127.0.0.1:6379> get k1
"helloworld"
127.0.0.1:6379> setrange k1 1 java
(integer) 10
127.0.0.1:6379> get k1
"hjavaworld"
setex 设置键值,并设置过期时间
127.0.0.1:6379> setex <key> <过期时间(秒)> <value>
getset 以旧换新,设置新值同时返回旧值
# 如果旧值未设置过,就返回 null
127.0.0.1:6379
2.2.3、数据结构
String 的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS)。是可以修改的字符串,内部结构上类似于 Java 的 ArrayList,采用分配冗余空间的方式来减少内存的频繁分配。
如图所示,内部为当前字符串实际分配的空间 capacity 一般要高于实际字符串长度 len。当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次会多扩容 1M 的空间。
注:字符串最大长度为 512M。
2.3、Redis 中的列表类型操作(List)
2.3.1、简介
redis列表是简单的字符串列表,按照插入顺序排序。
你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
它的底层实际上是使用双向链表实现的,对两端的操作性能很高,通过索引下标操作中间节点性能会较差。
2.3.2、常用命令
操作 | 作用 |
---|---|
lpush | 从左边插入一个或多个值 |
rpush | 从右边插入一个或多个值 |
lrange | 从列表左边获取指定范围的值 |
lpop | 从左边弹出多个元素 |
rpop | 从右边弹出多个元素 |
rpoplpush | 从一个列表右边弹出一个元素放到另外一个列表中 |
lindex | 获取指定位置的索引 |
llen | 获取列表的长度 |
linsert | 在某一个值的前/后插入一个值 |
lrem | 删除指定数量的某个元素 |
lset | 替换指定位置的值 |
lpush/rpush 从左/右边插入一个或多个值
127.0.0.1:6379> lpush/rpush <key> <value1> <value2>
lrange 从列表左边获取指定范围的值
127.0.0.1:6379> lrange <key> <start> <stop>
返回列表 key 中指定区间 [start, stop] 内的元素,区间以偏移量 start 和 stop 指定。
下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
返回值:一个列表,包含指定区间内的元素
示例
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> rpush course java c c++ php js nodejs #course 集合的右边插入6个元素
(integer) 6
127.0.0.1:6379> lrange course 0 -1 #取出course集合中所有元素
"java"
"c"
"c++"
"php"
"js"
"nodejs"
127.0.0.1:6379> lrange course 1 3 #获取 course 集合索引 [1,3] 范围内的元素
"c"
"c++"
"php
lpop/rpop 从左/右边弹出多个元素
127.0.0.1:6379> lpop/rpop <key> <count>
count 可以省略,默认为 1
lpop/rpop 之后,弹出来的值会从 list 中删除
list 为空之后,键会被删除
rpoplpush 从一个列表右边弹出一个元素放到另外一个列表中
# 从 source 的右边弹出一个元素放到 destination 列表的左边,并返回被弹出的值
127.0.0.1:6379> rpoplpush source destination
lindex 获取指定索引位置的元素
# 返回列表 key 中,下标为 index 的元素;
127.0.0.1:6379> lindex key index
index:0:表示第一个元素,-1:表示最后一个元素;
如果 key 不是列表类型,则返回一个错误;
如果 index 超出了列表的范围,则返回 null;
llen 获取列表的长度
# 返回列表的长度;
127.0.0.1:6379> llen key
如果 index 超出了列表的范围,则返回 null;
如果 key 不是列表类型,返回一个错误;
linsert 在某一个值的前/后插入一个值
# 将 newvalue 插入到 value 的前/后;
127.0.0.1:6379> linsert <key> before|after <value> <newvalue>
当 value 不存在时,不做任何操作;
当 key 不存在时,列表为空,不做任何操作;
当 key 不是列表类型时,返回一个错误;
返回值:
- 命令执行成功,返回插入后的列表长度;
- vlaue 不存在,返回 -1;
- key 不存在,或 key 不为列表,返回 0;
lrem 删除指定数量的某个元素
# 根据参数 count 的值,移除列表中与参数 value 相等的元素
127.0.0.1:6379> lrem key count value
count 的值可以是以下几种:
- count > 0:从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count;
- count < 0:从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count;
- count = 0:移除表中所有与 value 相等的值;
返回值:
- 被移除元素的数量。
- 因为不存在的 key 被视作空表(empty list),所以当 key 不存在时,总是返回 0 。
lset 替换指定位置的值
# 将列表 key 下标为 index 的元素的值设置为 value 。
127.0.0.1:6379> lset <key> <index> <value>
当 index 参数超出范围,或对一个空列表( key 不存在)进行lset时,返回一个错误;
操作成功返回 ok ,否则返回错误信息。
2.3.3、数据结构
List 的数据结构为快速链表 quickList;首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也就是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当值比较多的时候才会改成 quickList。因为普通的链表需要的附加指针空间太大,会比较浪费空间,比如这个列表里存储的只是 int 类型的值,结构上还需要 2 个额外的指针 prev 和 next。
redis 将链表和 ziplist 结合起来组成了 quicklist。也就是将多个 ziplist 使用双向指针串起来使用,这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
2.4、Redis 中的集合类型操作(Set)
2.4.1、简介
redis set 对外提供的功与 list 类似,是一个列表的功能,特殊之处在于 set 是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择。
redis 的 set 是 string 类型的无序集合,他的底层实际是一个 value 为 null 的 hash 表,所以添加,删除,查找复杂度都是O(1)。
一个算法,如果时间复杂度是O(1),那么随着数据的增加,查找数据的时间不变,也就是不管数据多少,查找时间都是一样的。
2.4.2、常用命令
操作 | 作用 |
---|---|
sadd | 添加一个或多个元素 |
smembers | 取出所有元素 |
sismember | 判断集合中是否有某个值 |
scard | 返回集合中元素的个数 |
srem | 删除一个或多个元素 |
spop | 随机弹出指定数量的元素 |
srandmember | 随机获取指定数量的元素,不会从集合中删除 |
smove | 将某个元素从一个集合移动到另一个集合 |
sinter | 取多个集合的交集 |
sinterstore | 取多个集合的交集,放到一个新的集合 |
sunion | 取多个集合的并集,自动去重 |
sunionstore | 取多个集合的并集,放到一个新的集合 |
sdiff | 取多个集合的差集 |
sdiffstore | 取多个集合的差集,放到一个新的集合 |
sadd 添加一个或多个元素
# 向 key 中添加一个或多个元素,并自动去重
127.0.0.1:6379> sadd <key> <value1> <value2>
smembers 取出所有的元素
# 取出 set 集合中所有的元素
127.0.0.1:6379> smembers <key>
sismember 判断集合中是否有某个值
# 判断集合key中是否包含元素value
# 返回值:1 有;0 没有
127.0.0.1:6379> sismember <key> <value>
scard 返回集合中元素的个数
# 返回集合 key 的基数(集合中元素的数量);
# 当 key 不存在时,返回 0;
127.0.0.1:6379> scard <key>
srem 删除多个元素
# 移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略;
# 当 key 不是集合类型时,返回错误;
# 返回被成功移除的元素的数量;
127.0.0.1:6379> srem key member [member ...]
spop 随机弹出多个值
# 随机从 key 集合中弹出 count 个元素,count 默认值为 1;
127.0.0.1:6379> spop <key> <count>
返回被弹出的元素;
当 key 不存在(集合为空)时,返回 null;
当 count 大于集合的长度时,返回所有数据;
srandmember 随机获取多个元素,不会从集合中删除
# 从 key 指定的集合中随机返回 count 个元素,count 可以不指定,默认值是 1。
127.0.0.1:6379> srandmember <key> <count>
srandmember 和 spop的区别:
都可以随机获取多个元素,srandmember 不会删除元素,而spop会删除元素。
返回值:
只提供 key 参数时,返回一个元素;如果集合为空,返回 nil 。
如果提供了 count 参数,那么返回一个数组;如果集合为空,返回空数组
smove 将某个元素从一个集合移动到另一个集合
# 将 member 元素从 source 集合移动到 destination 集合。
127.0.0.1:6379> smove <source> <destination> member
smove 是原子性操作;
如果 source 集合不存在或不包含指定的 member 元素,则 smove 命令不执行任何操作,仅返回 0 。否则, member 元素从 source 集合中被移除,并添加到 destination 集合中去;
如果 destination 集合已经包含 member 元素时,smove 命令只是简单地将 source 集合中的 member 元素删除;
如果 source 或 destination 不是集合类型时,返回一个错误;
返回值:
- 如果 member 元素被成功移除,返回 1;
如果 member 元素不是 source 集合的成员,并且没有任何操作对 destination 集合执行,那么返回 0;
sinter 取多个集合的交集
127.0.0.1:6379> sinter key1 key2 [key3 ...]
sinterstore 将多个集合的交集放到一个新的集合中
# 这个命令类似于 sinter 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集;
# 返回结果集中的成员数据;
127.0.0.1:6379> sinterstore destination key [key ...]
sunion 去多个集合的并集,自动去重
127.0.0.1:6379> sunion key [key ...]
sunionstore 将多个集合的并集放到一个新的集合中
# 这个命令类似于 sunion 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集;
# 返回结果集中的成员数量
127.0.0.1:6379> sinterstore destination key [key ...]
sdiff 取多个集合的差集
# 如果结果为空,则返回一个空数组
127.0.0.1:6379> sdiff key [key ...]
sdiffstore 将多个集合的差集放到一个新的集合中
# 这个命令类似于 sdiff 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集;
# 结果集中的成员数量;
127.0.0.1:6379> sdiffstore destination key [key ...]
2.4.3、数据结构
set 数据结构是字典,字典是用 hash 表实现的;
Java 中的 HashSet 的内部实现使用 HashMap,只不过所有的 value 都指向同一个对象;
Redis 的 set 结构也是一样的,它的内部也使用 hash 结构,所有的 value 都指向同一个内部值;
2.5、Redis 中的哈希类型操作(Hash)
2.5.1、简介
Redis hash是一个键值对集合;
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象;
类似于java里面的Map<String,Object>;
2.5.2、常用命令
操作 | 作用 |
---|---|
hset | 设置多个 field 的值 |
hget | 返回指定的 field 的值 |
hgetall | 返回所有的域和值 |
hmset | 和 hset 类似(已弃用) |
hexists | 判断给定的 field 是否存在 |
hkeys | 返回所有的 field |
hvals | 返回所有的 value |
hlen | 返回 field 的数量 |
hincrby | 在 field 的值加上指定的数量 |
hsetnx | 当 field 不存在时,设置 field 的值 |
hset 设置多个 field 的值
# 将哈希表 key 中的域 field 的值设为 value 。
127.0.0.1:6379> hset key field value [field value ...]
如果 key 不存在,一个新的哈希表被创建并进行 hset 操作;
如果域 field 已经存在于哈希表中,旧值将被覆盖;
返回值:
- 如果 field 是哈希表中的一个新建域,并且值设置成功,返回 1;
- 如果哈希表中域 field 已经存在且旧值已被新值覆盖,返回 0;
hget 获取指定 field 的值
127.0.0.1:6379> hget key field
hgetall 返回 hash 中所有的域和值
127.0.0.1:6379> hgetall key
hmset 和 hset 类似(已弃用)
127.0.0.1:6379> hmset key field value [field value ...]
hexists 判断给定的 field 是否存在
# 存在返回 1,不存在返回 0
127.0.0.1:6379> hexists key field
hkeys 列出所有的 field
127.0.0.1:6379> hkeys key
hvals 列出所有的 value
127.0.0.1:6379> hvals key
hlen 返回 field 的数量
# 当 key 不存在时,返回 0
127.0.0.1:6379> hlen key
hincrby 在 field 的值加上指定的数量
127.0.0.1:6379> hincrby key field increment
为哈希表 key 中的域 field 的值加上增量 increment 。
增量也可以为负数,相当于对给定域进行减法操作。
如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。
如果域 field 不存在,那么在执行命令前,域的值被初始化为 0 。
对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误。
返回值:
执行 hincrby 命令之后,哈希表 key 中域 field 的值。
hsetnx 当 field 不存在时,设置 field 的值
127.0.0.1:6379> hsetnx key field value
将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在。
若域 field 已经存在,该操作无效。
如果 key 不存在,一个新哈希表被创建并执行 hsetnx 命令。
返回值:
设置成功,返回 1 。
如果给定域已经存在且没有操作被执行,返回 0
2.5.3、数据结构
Hash 类型对应的数据结构是 2 中:ziplist(压缩列表),hashtable(哈希表)。
当 field-value 长度较短个数较少时,使用 ziplist,否则使用 hashtable。
2.6、Redis 中的有序集合操作(Zset)
2.6.1、简介
redis 有序集合 zset 与普通集合 set 非常相似,是一个没有重复元素的字符串集合。
不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。
集合的成员是唯一的,但是评分是可以重复的。
因为元素是有序的,所以你可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。
访问有序集合中的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员你的智能列表。
2.6.2、常用命令
操作 | 作用 |
---|---|
zadd | 添加一个或多个元素 |
zrange | 返回指定索引范围的元素(score 升序) |
zrevrange | 返回指定索引范围的元素(score 降序) |
zrangebyscore | 返回指定 score 范围的元素(score 升序) |
zrevrangebyscore | 返回指定 score 范围的元素(score 降序) |
zincrby | 为指定元素的 score 加上指定的数量 |
zrem | 删除集合中一个或多个元素 |
zremrangebyrank | 删除指定索引范围元素 |
zrenrangebyscore | 删除指定 score 范围元素 |
zcount | 返回指定 score 范围内元素的个数 |
zrank | 返回某个元素在集合中的排名(score 升序) |
zrevrank | 返回某个元素在集合中的排名(score 降序) |
zscore | 返回集合中指定元素的 score |
zadd 添加元素
127.0.0.1:6379> zadd <key> <score1> <member1> <score2> <member2> ...
将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入
这个 member 元素,来保证该 member 在正确的位置上。
score 值可以是整数值或双精度浮点数。
如果 key 不存在,则创建一个空的有序集并执行 zadd 操作。
当 key 存在但不是有序集类型时,返回一个错误。
返回值:
被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员
zrange 或者指定索引范围的元素(score 升序)
127.0.0.1:6379> zrange key start top [withscores]
返回存储在有序集合 key 中的指定范围的元素。 返回的元素可以认为是按score从最低到最高排列,如果得分相同,将按字典排序。
下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。
你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
zrange key 0 -1:可以获取所有元素
withscores:让成员和它的 score 值一并返回,返回列表以 value1, score1, …, valueN, scoreN 的格式表示
可用版本:>= 1.2.0
**时间复杂度:**O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
**返回值:**指定区间内,带有 score 值(可选)的有序集成员的列表。
zrevrange 获取指定索引范围的元素(score 降序)
# 和 zrange 用法一致
127.0.0.1:6379> zrevrange key start stop [WITHSCORES]
zrangebyscore 获取指定 score 范围内的数据(score 升序)
127.0.0.1:6379> zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
具有相同 score 值的成员按字典序来排列(该属性是有序集提供的,不需要额外的计算)。
可选的 LIMIT 参数指定返回结果的数量及区间(就像SQL中的 SELECT LIMIT offset, count),注意当 offset 很大时,定位 offset 的操作可能需要遍历整个有序集,此过程最坏复杂度为 O(N) 时间。
可选的 WITHSCORES 参数决定结果集是单单返回有序集的成员,还是将有序集成员及其 score 值一起返回。
zrevrangebyscore 获取指定 score 范围内的数据(score 降序)
# 和 zrangebyscore 一致
127.0.0.1:6379> zrevrangebyscore key max min [WITHSCORES] [LIMIT offset count]
zincrby 为指定元素的 score 增加上指定的数量
127.0.0.1:6379> zincrby key increment member
为有序集 key 的成员 member 的 score 值加上增量 increment 。
可以通过传递一个负数值 increment ,让 score 减去相应的值,比如 ZINCRBY key -5 member ,就是让 member 的 score 值减去 5 。
当 key 不存在,或 member 不是 key 的成员时, ZINCRBY key increment member 等同于 ZADD key increment member 。
当 key 不是有序集类型时,返回一个错误。
score 值可以是整数值或双精度浮点数。
zrem 删除集合中多个元素
# 移除有序集 key 中的一个或多个成员,不存在的成员将被忽略;
# 当 key 存在但不是有序集类型时,返回一个错误;
127.0.0.1:6379> zrem key member [member ...]
zremrangebyrank 根据索引范围删除元素
127.0.0.1:6379> zremrangebyrank key start stop
移除有序集 key 中,指定排名(rank)区间内的所有成员。
区间分别以下标参数 start 和 stop 指出,包含 start 和 stop 在内。
下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。
你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
返回结果:
当成功删除时,返回 1;
当 key 不存在或 key 为空时,返回 0;
当 key 不为 zset 时,报错;
zremrangebyscore 根据 score 范围删除元素
# 和 zremrangebyrank 用法一致
127.0.0.1:6379> zremrangebyscore key min max
zcount 统计指定 score 范围内元素的个数
127.0.0.1:6379> zcount key min max
返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量
返回值:
当 key 不存在或 key 为空时,返回 0;
当 key 不为 zset 时,报错;
zrank 返回某个元素在集合中的排名(score 升序)
127.0.0.1:6379> zrank key member
排名以 0 为底,也就是说, score 值最小的成员排名为 0 。
**返回值:**member 的排名
当 key 不存在或 member 为空时,返回 null;
当 key 不为 zset 时,报错;
zrevrank 返回某个元素在集合中的排名(score 降序)
# 和 zrank 用法一致
127.0.0.1:6379> zrevrank key member
zscore 返回集合中指定元素的 score
127.0.0.1:6379> zscore key member
返回有序集 key 中,成员 member 的 score 值。
如果 member 元素不是有序集 key 的成员,或 key 不存在,返回 nil 。
2.6.3、数据结构
SortedSet(zset)是 redis 提供的一个非常特别的数据结构,内部使用到了2种数据结构。
1、hash 表
类似于 java 中的 Map<String,score>,key 为集合中的元素,value 为元素对应的 score,可以用来快速定位元素定义的 score,时间复杂度为 O(1)
2、跳表
跳表(skiplist)是一个非常优秀的数据结构,实现简单,插入、删除、查找的复杂度均为 O(logN)。类似 java 中的 ConcurrentSkipListSet,根据 score 的值排序后生成的一个跳表,可以快速按照位置的顺序或者 score 的顺序查询元素。这里我们来看一下跳表的原理:
首先从考虑一个有序表开始:
从该有序表中搜索元素 < 23, 43, 59 > ,需要比较的次数分别为 < 2, 4, 6 >,总共比较的次数为 2 + 4 + 6 = 12 次。有没有优化的算法吗? 链表是有序的,但不能使用二分查找。类似二叉搜索树,我们把一些节点提取出来,作为索引。得到如下结构:
这里我们把 < 14, 34, 50, 72 > 提取出来作为一级索引,这样搜索的时候就可以减少比较次数了。我们还可以再从一级索引提取一些元素出来,作为二级索引,变成如下结构:
这里元素不多,体现不出优势,如果元素足够多,这种索引结构就能体现出优势来了。