?个人公众号:? :??? 可为编程? ?? ?个人信条:? 知足知不足 有为有不为 为与不为皆为可为? ?本篇简介:? 本篇记录Redis五种数据类型及命令操作,如有出入还望指正。
Redis中的Hash是一个键值对集合。Redis Hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。类似于java里面的Map<String,Object>集合一样,如果内存足够大的话,一个Redis的Hash结构可以存储2的32次幂-1个键值对,相当于40亿条数据,其实Hash类型的vlue在Redis中存储时其存储的还是String类型的字符串。下面就针对Hash的一些命令进行实战化演练。
hset key field value [field value ...]
将哈希表
key
中的域field
的值设为value
。 如果key
不存在,一个新的哈希表被创建并进行 hset 操作。 如果域field
已经存在于哈希表中,旧值将被覆盖。 返回值: 如果field
是哈希表中的一个新建域,并且值设置成功,返回1
。 如果哈希表中域field
已经存在且旧值已被新值覆盖,返回0
。
示例
hget key field
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 18#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hget user name #获取user中的name
"kewei"
hgetall key
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 18#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hgetall user #获取user所有信息
1)"name"
2)"kewei"
3)"age"
4)"18"
hmset key field value [field value ...]
hexists key field
查看哈希表
key
中,给定域field
是否存在。 返回值: 如果哈希表含有给定域,返回1
。 如果哈希表不含有给定域,或key
不存在,返回0
。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 30#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hexists user name #user中存在name域
(integer)1
127.0.0.1:6379> hexists user address #user中不存在address域,返回0
(integer)0
127.0.0.1:6379> hexists user1 address #user1这个key不存在,返回0
(integer)0
hkeys key
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 30#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hkeys user #获取user中的所有filed
1)"name"
2)"age"
hvals key
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 30#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hvals user #获取user中的所有filed的值列表
1)"kewei"
2)"30"
HLEN key
返回哈希表
key
中域的数量。 返回值: 哈希表中域的数量。 当key
不存在时,返回0
。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 30#哈希表user中设置2个域:name和age,name的值为kewei,age的值为30
(integer)2
127.0.0.1:6379> hlen user
(integer)2
hincrby key field increment
为哈希表 key 中的域 field 的值加上增量 increment 。增量也可以为负数,相当于对给定域进行减法操作。如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。如果域 field 不存在,那么在执行命令前,域的值被初始化为 0。如果对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误,因此只有当值为整型时才会起作用。 返回值: 执行 hincrby 命令之后,哈希表
key
中域field
的值。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset siteInfo site kewei pv 1000#hash表siteInfo中有2个域:{site:"kewei",pv:1000}
(integer)2
127.0.0.1:6379> hget siteInfo pv #获取siteInfo中pv的值
"1000"
127.0.0.1:6379> hincrby siteInfo pv 10#siteInfo中的pv值增加10
(integer)1010
127.0.0.1:6379> hget siteInfo pv #获取siteInfo中的pv
"1010"
127.0.0.1:6379> hincrby siteInfo uv 500#siteInfo中的uv值增加500,uv这个域不存在,则会先添加,然后再执行hincrby
(integer)500
hsetnx key field value
将哈希表
key
中的域field
的值设置为value
,当且仅当域field
不存在。 若域field
已经存在,该操作无效。 如果key
不存在,一个新哈希表被创建并执行 hsetnx 命令。 返回值: 设置成功,返回1
。 如果给定域已经存在且没有操作被执行,返回0
。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> hset user name kewei age 30#创建user,包含2个域:name、age
(integer)2
127.0.0.1:6379> hsetnx user name tom #name已存在,设置失败,返回0
(integer)0
127.0.0.1:6379> hget user name #name依旧是kewei
"kewei"
127.0.0.1:6379> hsetnx user address shanghai #address不存在,设置成功
(integer)1
127.0.0.1:6379> hget user address #输出address的值
"shanghai"
Hash类型对应的数据结构是2种:一种是ziplist(压缩列表),第二种时hashtable(哈希表)。当存储的数据不多时采用ziplist,当超过配置文件中的阈值时,采用hashtable进行存储。当field-vaklue长度较短个数较少时,使用ziplist,否则使用hashtable。
Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个分数(score),这个分数(score)被用来按照从最低分到最高分的方式排序集合中的成员。ZSet 有两种不同的实现,分别是ziplist(压缩表)和skiplist(跳表)。具体使用哪种结构进行存储,规则如下:
ziplist
满足以下两个条件:
skiplist
:不满足以上两个条件时使用跳表、组合了 hash 和 skiplist
因为元素是有序的,所以可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。
zadd <key><score1><member1><score2><member2>...
将一个或多个
member
元素及其score
值加入到有序集key
当中。 如果某个member
已经是有序集的成员,那么更新这个member
的score
值,并通过重新插入这个member
元素,来保证该member
在正确的位置上。score
值可以是整数值或双精度浮点数。 如果key
不存在,则创建一个空的有序集并执行 zadd 操作。 当key
存在但不是有序集类型时,返回一个错误。 返回值: 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topn 100 java 80 c 90 c++50 php 70 js #创建名称为topn的zset,添加了5个元素
(integer)5
zrange key start top [withscores]
key
中的指定范围的元素。返回的元素可以认为是按score从最低到最高排列,如果得分相同,将按字典排序。
start
和 stop
都以 0
为底,也就是说,以 0
表示有序集第一个成员,以 1
表示有序集第二个成员,以此类推。
你也可以使用负数下标,以 -1
表示最后一个成员, -2
表示倒数第二个成员,以此类推。
score
值一并返回,返回列表以 value1,score1, ..., valueN,scoreN
的格式表示
可用版本:
>= 1.2.0
时间复杂度:
O(log(N)+M), N
为有序集的基数,而 M
为结果集的基数。
返回值:
指定区间内,带有 score
值(可选)的有序集成员的列表。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topn 100 java 80 c 90 c++ 50 php 70 js #创建名称为topn的zset,添加了5个元素
(integer)5
127.0.0.1:6379> zrange topn 0 -1#按score升序,返回topn中所有元素的值
1)"php"
2)"js"
3)"c"
4)"c++"
5)"java"
127.0.0.1:6379> zrange topn 0 -1 withscores #按score升序,返回所有元素的值以及score
1)"php"
2)"50"
3)"js"
4)"70"
5)"c"
6)"80"
7)"c++"
8)"90"
9)"java"
10)"100"
127.0.0.1:6379> zrange topn 24#返回索引范围[2,4]内的3个元素
1)"c"
2)"c++"
3)"java"
zrevrange key start stop [WITHSCORES]
key
中的指定范围的元素。返回的元素可以认为是按score最高到最低排列, 如果得分相同,将按字典排序。
start
和 stop
都以 0
为底,也就是说,以 0
表示有序集第一个成员,以 1
表示有序集第二个成员,以此类推。
你也可以使用负数下标,以 -1
表示最后一个成员, -2
表示倒数第二个成员,以此类推。
score
值一并返回,返回列表以 value1,score1, ..., valueN,scoreN
的格式表示
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topn 100 java 80 c 90 c++50 php 70 js #创建名称为topn的zset,添加了5个元素
(integer)5
127.0.0.1:6379> zrevrange topn 0-1#按照score降序获取所有元素
1)"java"
2)"c++"
3)"c"
4)"js"
5)"php"
127.0.0.1:6379> zrevrange topn 02#按照score降序获取前3名
1)"java"
2)"c++"
3)"c"
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
值一起返回。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topn 100 java 80 c 90 c++50 php 70 js #创建名称为topn的zset,添加了5个元素
(integer)5
127.0.0.1:6379> zrangebyscore topn 7090#score升序,获取score位于[70,90]区间中的元素值
1)"js"
2)"c"
3)"c++"
127.0.0.1:6379> zrangebyscore topn 7090 withscores #score升序,获取score位于[70,90]区间中的元素值及score
1)"js"
2)"70"
3)"c"
4)"80"
5)"c++"
6)"90"
127.0.0.1:6379> zrangebyscore topn 7090 withscores limit 12#相当于:select value,score from topn集合 where score>=70 and score<=90 order by score asc limit 1,2
1)"c"
2)"80"
3)"c++"
4)"90"
zrevrangebyscore key max min [WITHSCORES][LIMIT offset count]
返回有序集
key
中,score
值介于max
和min
之间(默认包括等于max
或min
)的所有的成员。有序集成员按score
值递减(从大到小)的次序排列。 具有相同score
值的成员按字典序的逆序排列。 除了成员按score
值递减的次序排列这一点外, zrevrangebyscore 命令的其他方面和 zrangebyscore 命令一样。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topn 100 java 80 c 90 c++50 php 70 js #创建名称为topn的zset,添加了5个元素
(integer)5
127.0.0.1:6379> zrevrangebyscore topn 10090#score降序,获取score位于[70,90]区间中的元素值
1)"java"
2)"c++"
127.0.0.1:6379> zrevrangebyscore topn 10090 withscores #score降序,获取score位于[70,90]区间中的元素值及score
1)"java"
2)"100"
3)"c++"
4)"90"
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
值可以是整数值或双精度浮点数。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++#集合topx中添加3个元素:java、c、c++,对应的score分别是:90、70、80
(integer)3
127.0.0.1:6379> zrevrange topx 0-1 withscores #输出集合topx中的元素,包含score
1)"java"
2)"90"
3)"c++"
4)"80"
5)"c"
6)"70"
127.0.0.1:6379> zincrby topx 5 java #对topx中的元素java的score加5,变成95了
"95"
127.0.0.1:6379> zrevrange topx 0-1 withscores # 输出集合元素,注意java的score是95了
1)"java"
2)"95"
3)"c++"
4)"80"
5)"c"
6)"70"
zrem key member [member ...]
移除有序集
key
中的一个或多个成员,不存在的成员将被忽略。 当key
存在但不是有序集类型时,返回一个错误。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++#集合topx中添加3个元素:java、c、c++,对应的score分别是:90、70、80
(integer)3
127.0.0.1:6379> zrange topx 0-1#输出集合topx中所有元素
1)"c"
2)"c++"
3)"java"
127.0.0.1:6379> zrem topx c c++#删除集合topx中的2个元素:c、c++
(integer)2
127.0.0.1:6379> zrange topx 0-1#输出集合topx中所有元素
1)"java"
zremrangebyrank key start stop
移除有序集
key
中,指定排名(rank)区间内的所有成员。 区间分别以下标参数start
和stop
指出,包含start
和stop
在内。 下标参数start
和stop
都以0
为底,也就是说,以0
表示有序集第一个成员,以1
表示有序集第二个成员,以此类推。 你也可以使用负数下标,以-1
表示最后一个成员,-2
表示倒数第二个成员,以此类推。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++#集合topx中添加3个元素:java、c、c++,对应的score分别是:90、70、80
(integer)3
127.0.0.1:6379> zrange topx 0-1#输出集合topx中所有元素
1)"c"
2)"c++"
3)"java"
127.0.0.1:6379> zremrangebyrank topx 01#删除索引范围[0,1]的数据
(integer)2
127.0.0.1:6379> zrange topx 0-1#输出topx中所有元素
1)"java"
zremrangebyscore key min max
移除有序集
key
中,所有score
值介于min
和max
之间(包括等于min
或max
)的成员
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++50 php #topx集合中添加4个元素
(integer)4
127.0.0.1:6379> zrange topx 0 -1 withscores #输出topx中所有元素值、score
1)"php"
2)"50"
3)"c"
4)"70"
5)"c++"
6)"80"
7)"java"
8)"90"
127.0.0.1:6379> zremrangebyscore topx 7080#删除score位于[70,80]区间的元素
(integer)2
127.0.0.1:6379> zrange topx 0 -1 withscores #输出剩下的元素
1)"php"
2)"50"
3)"java"
4)"90"
zcount key min max
返回有序集
key
中,score
值在min
和max
之间(默认包括score
值等于min
或max
)的成员的数量
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++50 php #topx集合中添加4个元素
(integer)4
127.0.0.1:6379> zcount topx 80100#统计score位于[80,100]区间中的元素个数
(integer)2
zrank key member
返回有序集
key
中成员member
的排名。其中有序集成员按score
值递增(从小到大)顺序排列。 排名以0
为底,也就是说,score
值最小的成员排名为0
。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++50 php #topx集合中添加4个元素
(integer)4
127.0.0.1:6379> zrank topx c #获取元素c的排名,返回1表示排名第2
(integer)1
127.0.0.1:6379> zrange topx 0-1#输出集合中所有元素,看一下c的位置确实是2
1)"php"
2)"c"
3)"c++"
4)"java"
返回有序集
key
中成员member
的排名。其中有序集成员按score
值递减(从大到小)排序。 排名以0
为底,也就是说,score
值最大的成员排名为0
。
示例
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++50 php #topx集合中添加4个元素
(integer)4
127.0.0.1:6379> zrange topx 0-1
1)"php"
2)"c"
3)"c++"
4)"java"
127.0.0.1:6379> zrevrank topx java #score降序,得到java的排名,排在第1位
(integer)0
zscore key member
返回有序集
key
中,成员member
的score
值。 如果member
元素不是有序集key
的成员,或key
不存在,返回nil
。
127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> zadd topx 90 java 70 c 80 c++50 php #topx集合中添加4个元素
(integer)4
127.0.0.1:6379> zrange topx 0-1#输出topx集合所有元素
1)"php"
2)"c"
3)"c++"
4)"java"
127.0.0.1:6379> zscore topx java #获取集合topx中java的score
"90"
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 > 提取出来作为一级索引,这样搜索的时候就可以减少比较次数了。我们还可以再从一级索引提取一些元素出来,作为二级索引,变成如下结构:
这里元素不多,体现不出优势,如果元素足够多,这种索引结构就能体现出优势来了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。