您当前的位置: 首页 >  大数据

Dongguo丶

暂无认证

  • 2浏览

    0关注

    472博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

常见五大数据类型

Dongguo丶 发布时间:2021-10-28 08:07:49 ,浏览量:2

redis常见数据类型操作命令http://www.redis.cn/commands.html

Redis键(key)

redis是键值(key-value)型存储数据库,

关于key的定义,需要注意:

1、key不要太长,最好不要超过1024个字节,这不仅会消耗内存还会降低查询效率

2、key不要太短,如果太短会降低key的可读性

3、在项目中,key最好有一个统一的命名规范

key相关命令:

keys * 查看当前库所有key  (匹配:keys *1)
    redis有多个库,默认使用0号库

exists key 判断某个key是否存在

type key 查看你的key是什么类型

del key    删除指定的key数据

unlink key  根据value选择非阻塞删除

仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。

expire key 10  10秒钟:为给定的key设置过期时间

ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期

 
扩展:
select index 命令切换数据库

dbsize 查看当前数据库的key的数量

flushdb 清空当前库

flushall 清空全部库
keys *

keys pattern:获取所有与pattern匹配的key,返回所有与该key匹配的keys。*表示任意一个或多个字符, ?表示任意一个字符

由于redis中还没有数据,现加入几条数据以供测试。

127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set k1 zhangsan
OK
127.0.0.1:6379> set k2 lisi
OK
127.0.0.1:6379> set k3 wangwu
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
3) "k3"
127.0.0.1:6379> keys k?
1) "k1"
2) "k2"
3) "k3"
exists key
127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> exists k
(integer) 0
127.0.0.1:6379> 

1表示存在,0表示不存在

type key
127.0.0.1:6379> type k1
string
127.0.0.1:6379> 
del key/unlink key
127.0.0.1:6379> del k3
(integer) 1
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379> 
127.0.0.1:6379> unlink k2
(integer) 1
127.0.0.1:6379> keys *
1) "k1"
127.0.0.1:6379> 

这两个命令使用起来看似相似,但是

del key 是删除指定的key数据

unlink key仅将keys从keyspace元数据中删除,真正的删除会在后续进行异步操作。

expire key 10/ttl key

expire key :设置过期时间 ,单位:秒

ttl key:获取该key所剩的超时时间,如果没有设置超时,返回-1,如果返回-2表示已超时key不存在了。

127.0.0.1:6379> expire k1 10
(integer) 1
127.0.0.1:6379> ttl k1
(integer) 5
127.0.0.1:6379> ttl k1
(integer) -2
127.0.0.1:6379> 
rename key newkey:为当前的key重命名
127.0.0.1:6379> get k1
"zhangsan"
127.0.0.1:6379> rename k1 k11
OK
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> get k11
"zhangsan"
Redis字符串(String) 简介

String是Redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。

String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象。

String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M

常用命令 set 添加键值对

设定key持有指定的字符串value,如果该key存在则进行覆盖 操作。总是返回”OK”

image-20211027193344580

*NX:当数据库中key不存在时,可以将key-value添加数据库

*XX:当数据库中key存在时,可以将key-value添加数据库,与NX参数互斥

*EX:key的超时秒数

*PX:key的超时毫秒数,与EX互斥

127.0.0.1:6379> set k1 v001
OK
127.0.0.1:6379> set k2 v002
OK
127.0.0.1:6379> 
127.0.0.1:6379> set k2 v1002
OK
127.0.0.1:6379> get k2
"v1002"

设置相同的key,value会被覆盖

get 查询对应键值

获取key的value。如果与该key关联的value不是String类型,redis 将返回错误信息,因为get命令只能用于获取String value;如果该key不存在,返回null。

[root@dongguo bin]# redis-cli
127.0.0.1:6379> get k1
"v001"
127.0.0.1:6379> get k2
"v002"
127.0.0.1:6379>
append 将给定的 追加到原值的末尾

如果该key存在,则在原有的value后追加该值;如果该 key 不存在,则重新创建一个key/value

127.0.0.1:6379> append k1 abc
(integer) 7
127.0.0.1:6379> get k1
"v001abc"
127.0.0.1:6379> 
strlen 获得值的长度
127.0.0.1:6379> strlen k1
(integer) 7
127.0.0.1:6379> 
setnx 只有在 key 不存在时 设置 key 的值
127.0.0.1:6379> setnx k2 v2
(integer) 0
127.0.0.1:6379> get k2
"v1002"
127.0.0.1:6379> setnx k3 v003
(integer) 1
127.0.0.1:6379> get k3
"v003"
127.0.0.1:6379> 

string 操作setnx可以作为分布式锁

incr 将 key 中储存的数字值增1

只能对数字值操作,如果为空,新增值为1

将指定的key的value原子性的递增1.如果该key不存在,其初始值为0,在incr之后其值为1。如果value的值不能转成整型,如hello,该操作将执 行失败并返回相应的错误信息。

decr 将 key 中储存的数字值减1

只能对数字值操作,如果为空,新增值为-1

将指定的key的value原子性的递减1.如果该key不存在,其初始值 为0,在incr之后其值为-1。如果value的值不能转成整型,如hello,该操作将执 行失败并返回相应的错误信息。

127.0.0.1:6379> set k4 100
OK
127.0.0.1:6379> incr k4
(integer) 101
127.0.0.1:6379> decr k4
(integer) 100
127.0.0.1:6379> 
incrby / decrby 将 key 中储存的数字值增减。自定义步长。

incrby key increment:将指定的key的value原子性增加increment,如果该 key不存在,器初始值为0,在incrby之后,该值为increment。如果该值不能转成 整型,如hello则失败并返回错误信息

decrby key decrement:将指定的key的value原子性减少decrement,如果 该key不存在,器初始值为0,在decrby之后,该值为decrement。如果该值不能 转成整型,如hello则失败并返回错误信息

127.0.0.1:6379> incrby k4 10
(integer) 110
127.0.0.1:6379> decrby k4 10
(integer) 100
127.0.0.1:6379> 
mset …

同时设置一个或多个 key-value对

127.0.0.1:6379> mset k5 v5 k6 v6 k7 v7
OK
mget …

同时获取一个或多个 value

127.0.0.1:6379> mget k5 k6 k7
1) "v5"
2) "v6"
3) "v7"
msetnx …

同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。

127.0.0.1:6379> msetnx k1 v1 k8 v8 k9 v9
(integer) 0
127.0.0.1:6379> msetnx k8 v8 k9 v9 k10 v10
(integer) 1
getrange

获得值的范围,类似java中的substring,前包,后包

127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> getrange name 0 5
"zhangs"
setrange

用 覆写所储存的字符串值,从开始(索引从0开始)。

127.0.0.1:6379> setrange name 5 123
(integer) 8
127.0.0.1:6379> get name
"zhang123"
setex

设置键值的同时,设置过期时间,单位秒。

127.0.0.1:6379> setex name 20 zhangsan
OK
127.0.0.1:6379> ttl name
(integer) 16
127.0.0.1:6379> ttl name
(integer) 10
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> 
getset

以新换旧,设置了新值同时获得旧值。

127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> getset name lisi
"zhangsan"
127.0.0.1:6379> get name
"lisi"
del key:删除指定key
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> get name
(nil)
数据结构

String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS)。是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配.

image-20211027204625474

如图中所示,内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M。

Redis列表(List) 简介

单键多值

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是 4294967295。

它的底层实际是个双向链表,对两端的操作性能很高,,即使链表中已经存储了百万条记录,该操作也可以在常量时间 内完成。通过索引下标的操作中间的节点性能会较差。

image-20211027204749389

常用命令 lpush/rpush … 从左边/右边插入一个或多个值。
#清空数据库
127.0.0.1:6379> FLUSHDB
OK
#从左边插入一个或多个值。
127.0.0.1:6379> lpush k1 v1 v2 v3
(integer) 3
#按照索引下标获得元素(从左到右)  -1表示获得所有值
127.0.0.1:6379> lrange k1 0 -1
1) "v3"
2) "v2"
3) "v1"
127.0.0.1:6379> 
127.0.0.1:6379> rpush k2 v1 v2 v3
(integer) 3
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> 
lpushx key value:

仅当参数中指定的key存在时(如果与key管理的list中没有值时,则该key是不存在的)在指定的key所关联的list的头部插入value。

127.0.0.1:6379> lpushx k1 v0
(integer) 4
127.0.0.1:6379> lpushx k3 v0
(integer) 0
rpushx key value:

在该list的尾部添加元素

127.0.0.1:6379> rpushx k1 v4
(integer) 5
127.0.0.1:6379> rpushx k3 v4
(integer) 0
lpop/rpop 从左边/右边弹出一个值。值在键在,值光键亡。
127.0.0.1:6379> lpop k1
"v3"
127.0.0.1:6379> lrange k1 0 -1
1) "v2"
2) "v1"
127.0.0.1:6379> rpop k2
"v3"
127.0.0.1:6379> lrange k2 0 -1
1) "v1"
2) "v2"
127.0.0.1:6379> 
rpoplpush 从列表右边弹出一个值,插到列表左边。
127.0.0.1:6379> lpush k3 v31 v32 v33
(integer) 3
127.0.0.1:6379> lpush k4 v41 v42 v43
(integer) 3
127.0.0.1:6379> rpoplpush k3 k4
"v31"
127.0.0.1:6379> lrange k3 0 -1
1) "v33"
2) "v32"
127.0.0.1:6379> lrange k4 0 -1
1) "v31"
2) "v43"
3) "v42"
4) "v41"
127.0.0.1:6379> 
lrange

按照索引下标获得元素(从左到右)

lrange mylist 0 -1 0左边第一个,-1右边第一个,(0-1表示获取所有)

lindex 按照索引下标获得元素(从左到右)
127.0.0.1:6379> lindex k4 0
"v31"
127.0.0.1:6379> 
llen 获得列表长度

返回指定的key关联的链表中的元素的数量。

127.0.0.1:6379> llen k4
(integer) 4
127.0.0.1:6379> 
linsert before|after 在的后面/前面插入插入值
127.0.0.1:6379> linsert k4 after v31 v32
(integer) 5
127.0.0.1:6379> lrange k4 0 -1
1) "v31"
2) "v32"
3) "v43"
4) "v42"
5) "v41"
127.0.0.1:6379> 
lrem 从左边删除n个是value的值(从左到右)

删除count个值为value的元素,如果count大于0,从头向尾遍历并删除count个值为value的元素,如果count小于0,则从尾向头遍历并删除。如果count等于0,则删除链表中所有等于value的元素。

127.0.0.1:6379> lrange k4 0 -1
1) "v31"
2) "v32"
3) "v43"
4) "v42"
5) "v41"
127.0.0.1:6379> linsert k4 after v43 v32
(integer) 6
127.0.0.1:6379> linsert k4 after v42 v32
(integer) 7
127.0.0.1:6379> lrange k4 0 -1
1) "v31"
2) "v32"
3) "v43"
4) "v32"
5) "v42"
6) "v32"
7) "v41"
127.0.0.1:6379> lrem k4 2 v32
(integer) 2
127.0.0.1:6379> lrange k4 0 -1
1) "v31"
2) "v43"
3) "v42"
4) "v32"
5) "v41"
127.0.0.1:6379> 
lset将列表key下标为index的值替换成value

设置链表中的index的脚标的元素值,0代表链表的头元素,-1代表链表的尾元素。

127.0.0.1:6379> lset k4 0 v44
OK
127.0.0.1:6379> lrange k4 0 -1
1) "v44"
2) "v43"
3) "v42"
4) "v32"
5) "v41"
127.0.0.1:6379>
数据结构

List的数据结构为快速链表quickList。

首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。

它将所有的元素紧挨着一起存储,分配的是一块连续的内存。

当数据量比较多的时候才会改成quicklist。

因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。

image-20211027215105964

Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

使用场景

rpoplpush的使用场景:

Redis链表经常会被用于消息队列的服务,以完成多程序之间的消息交换。假设一个应用程序正在执行LPUSH操作向链表中添加新的元素,我们通常将这样的程序称之为“生产者(Producer",而另外一个应用程序正在执行RPOP操作从链表中取出元素,我们称这样的程序为"消费者(Consumer)".如果此时,消费者程序在取出消息元素后立刻崩溃,由于该消息已经被取出且没有被正常处理,那么我们就可以认为该消息已经丢失,由此可能会导致业务数据丢失,或业务状态的不一致等现象的发生。然而通过使用RPOPLPUSH命令,消费者程序在从主消息队列中取出消息之后再将其插入到备份队列中,直到消费者程序完成正常的处理逻辑后再将该消息从备份队列中删除。同时我们还可以提供一个守护进程,当发现备份队列中的消息过期时,可以重新将其再放回到主消息队列中,以便其它的消费者程序继续处理。

image-20211028070113029

Redis集合(Set) 简介

Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。和List类型相比,Set类 型在功能上还存在着一个非常重要的特性,即在服务器端完成多个Sets之间的聚合计 算操作,如unions、intersections和differences。由于这些操作均在服务端完成, 因此效率极高,而且也节省了大量的网络IO开销

Redis的Set是string类型的无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。

一个算法,随着数据的增加,执行时间的长短,如果是O(1),数据增加,查找数据的时间不变

Set可包含的最大元素数是4294967295。

常用命令 sadd …

将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd k1 v1 v2 v3
(integer) 3
smembers 取出该集合的所有值。
127.0.0.1:6379> smembers k1
1) "v2"
2) "v3"
3) "v1"
127.0.0.1:6379> 
sismember 判断集合是否为含有该值,有1,没有0
127.0.0.1:6379> sismember k1 v1
(integer) 1
127.0.0.1:6379> sismember k1 v4
(integer) 0
127.0.0.1:6379> 
scard返回该集合的元素个数。
127.0.0.1:6379> scard k1
(integer) 3
127.0.0.1:6379> 
srem … 删除集合中的某个元素。
127.0.0.1:6379> srem k1 v1
(integer) 1
127.0.0.1:6379> smembers k1
1) "v2"
2) "v3"
127.0.0.1:6379> 
spop 随机从该集合中取出一个值。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd k1 v1 v2 v3 v4 v5
(integer) 5
127.0.0.1:6379> smembers k1
1) "v4"
2) "v2"
3) "v3"
4) "v1"
5) "v5"
127.0.0.1:6379> spop k1
"v4"
127.0.0.1:6379> smembers k1
1) "v2"
2) "v3"
3) "v5"
4) "v1"
127.0.0.1:6379> spop k1
"v5"
127.0.0.1:6379> smembers k1
1) "v2"
2) "v3"
3) "v1"
127.0.0.1:6379> 

srandmember 随机从该集合中取出n个值。不会从集合中删除 。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd k1 v1 v2 v3 v4 v5
(integer) 5
127.0.0.1:6379> srandmember k1 2
1) "v4"
2) "v5"
127.0.0.1:6379> smembers k1
1) "v4"
2) "v2"
3) "v3"
4) "v1"
5) "v5"
127.0.0.1:6379> 
smove value把集合中一个值从一个集合移动到另一个集合
127.0.0.1:6379> sadd k2 v3 v4 v5 v6 v7
(integer) 5
127.0.0.1:6379> smove k1 k2 v3
(integer) 1
127.0.0.1:6379> smembers k1
1) "v2"
2) "v1"
3) "v4"
4) "v5"
127.0.0.1:6379> smembers k2
1) "v5"
2) "v6"
3) "v3"
4) "v4"
5) "v7"
127.0.0.1:6379> 
sinter 返回两个集合的交集元素。
127.0.0.1:6379> sinter k1 k2
1) "v4"
2) "v5"
sinterstore destination key1 key2:将返回的交集存储在destination上
127.0.0.1:6379> sinterstore k4 k1 k2
(integer) 3
127.0.0.1:6379> smembers k4
1) "v3"
2) "v4"
3) "v5"
sunion 返回两个集合的并集元素。
127.0.0.1:6379> sunion k1 k2
1) "v4"
2) "v2"
3) "v3"
4) "v5"
5) "v7"
6) "v6"
7) "v1"
sunionstore destination key1 key2:将返回的并集存储在destination上
127.0.0.1:6379> sunionstore  k5 k1 k2
(integer) 7
127.0.0.1:6379> smembers k5
1) "v3"
2) "v6"
3) "v2"
4) "v1"
5) "v5"
6) "v4"
7) "v7"
sdiff 返回两个集合的差集元素(key1中的,不包含key2中的)
127.0.0.1:6379> sdiff k1 k2
1) "v2"
2) "v1"
sdiffstore destination key1 key2:将key1与key2相差的成员存储在 destination上,仅是key1多的元素
127.0.0.1:6379> smembers k1
1) "v4"
2) "v3"
3) "v2"
4) "v1"
5) "v5"
127.0.0.1:6379> smembers k2
1) "v4"
2) "v3"
3) "v6"
4) "v5"
5) "v7"
127.0.0.1:6379> sdiffstore k3 k1 k2
(integer) 2
127.0.0.1:6379> smembers k3
1) "v2"
2) "v1"
数据结构

Set数据结构是dict字典,字典是用哈希表实现的。

Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。

使用场景

1、可以使用Redis的Set数据类型跟踪一些唯一性数据,比如访问某一博客的唯一IP地址信息。对于此场景,我们仅需在每次访问该博客时将访问者的IP存入Redis中, Set数据类型会自动保证IP地址的唯一性。

2、充分利用Set类型的服务端聚合操作方便、高效的特性,可以用于维护数据对象之间的关联关系。比如所有购买某一电子设备的客户ID被存储在一个指定的Set中,而购买另外一种电子产品的客户ID被存储在另外一个Set中,如果此时我们想获取有哪些客户同时购买了这两种商品时, Set的intersections命令就可以充分发挥它的方便和效率的优势了。

Redis哈希(Hash) 简介

Redis hash 是一个键值对集合。

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

类似Java里面的Map

用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储

主要有以下2种存储方式:

image-20211027221149659[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9nFhHwWb-1635379606481)(E:\笔记\图片\image\03常见五大数据类型.assets\image-20211027221231650.png)]每次修改用户的某个属性需要,先反序列化改好后再序列化回去。开销较大。用户ID数据冗余

使用hash:

image-20211027221405269

通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题

如果 Hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个Hash 可以存储4294967295个键值对。

常用命令 hset 给集合中的 键赋值
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> hset user:1001 id 1
(integer) 1
127.0.0.1:6379> hset user:1001 name zhangsan
(integer) 1
hget 从集合取出 value
127.0.0.1:6379> hget user:1001 id
"1"
127.0.0.1:6379> hget user:1001 name
"zhangsan"
127.0.0.1:6379> 
hmset … 批量设置hash的值
127.0.0.1:6379> hmset user:1002 id 2 name lisi age 18
OK
hmget key fileds:获取key中的多个filed的值
127.0.0.1:6379> hmget user:1002 id name
1) "2"
2) "lisi"
hexists查看哈希表 key 中,给定域 field 是否存在。
127.0.0.1:6379> hexists user:1001 id
(integer) 1
127.0.0.1:6379> hexists user:1001 age
(integer) 0
hkeys 列出该hash集合的所有field
127.0.0.1:6379> hkeys user:1002
1) "id"
2) "name"
3) "age"
hvals 列出该hash集合的所有value
127.0.0.1:6379> hvals user:1002
1) "2"
2) "lisi"
3) "18"
**hgetall key:**获取key中的所有filed-vaule
127.0.0.1:6379> hgetall user:1002
1) "id"
2) "2"
3) "name"
4) "lisi"
5) "age"
6) "18"
hlen key:获取key所包含的filed的数量
127.0.0.1:6379> hlen user:1002
(integer) 3
hincrby 为哈希表 key 中的域 field 的值加上增量
127.0.0.1:6379> hincrby user:1002 age 2
(integer) 20
hsetnx 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在 .
127.0.0.1:6379> hsetnx user:1002 age 30
(integer) 0
127.0.0.1:6379> hsetnx user:1002 gender 1
(integer) 1
127.0.0.1:6379> hkeys user:1002
1) "id"
2) "name"
3) "age"
4) "gender"
127.0.0.1:6379> hvals user:1002
1) "2"
2) "lisi"
3) "20"
4) "1"
数据结构

Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

Redis有序集合Zset(sorted set) 简介

Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。

不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。

因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。

访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。

事实上,Redis所具有的这一 特征在很多其它类型的数据库中是很难实现的,换句话说,在该点上要想达到和Redis 同样的高效,在其它数据库中进行建模是非常困难的。

例如:游戏排名、微博热点话题等使用场景。

常用命令 zadd …

将一个或多个 member 元素及其 score 值加入到有序集 key 当中。

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> zadd topn 80 zhangsan 89 lisi 60 wangwu 99 chenliu  
(integer) 4
zcard key:获取集合中的成员数量
127.0.0.1:6379> zcard topn
(integer) 4
zrange [WITHSCORES]

返回有序集 key 中,下标在 之间的元素

带WITHSCORES,可以让分数一起和值返回到结果集。从小到大

127.0.0.1:6379> zrange topn 0 -1
1) "wangwu"
2) "zhangsan"
3) "lisi"
4) "chenliu"
127.0.0.1:6379> zrange topn 0 -1 withscores
1) "wangwu"
2) "60"
3) "zhangsan"
4) "80"
5) "lisi"
6) "89"
7) "chenliu"
8) "99"
zrangebyscore key minmax [withscores] [limit offset count]

返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。

127.0.0.1:6379> zrangebyscore topn 80 100 withscores
1) "zhangsan"
2) "80"
3) "lisi"
4) "89"
5) "chenliu"
6) "99"
zrevrangebyscore key maxmin [withscores] [limit offset count]

同上,改为从大到小排列。

127.0.0.1:6379> zrevrangebyscore topn 100 80 withscores
1) "chenliu"
2) "99"
3) "lisi"
4) "89"
5) "zhangsan"
6) "80"
zincrby 为元素的score加上增量
127.0.0.1:6379> zincrby topn 10 wangwu
"70"
zcount 统计该集合,分数区间内的元素个数
127.0.0.1:6379> zcount topn 80 100
(integer) 3
zrank 返回该值在集合中的排名,从0开始。

从小到大

127.0.0.1:6379> zrange topn 0 -1 withscores
1) "wangwu"
2) "70"
3) "zhangsan"
4) "80"
5) "lisi"
6) "89"
7) "chenliu"
8) "99"
127.0.0.1:6379> zrank topn zhangsan
(integer) 1
zscore key member:返回指定成员的分数
127.0.0.1:6379> zscore topn zhangsan
"80"
zrem 删除该集合下,指定值的元素
127.0.0.1:6379> zrem topn zhangsan
(integer) 1
127.0.0.1:6379> zrange topn 0 -1 withscores
1) "wangwu"
2) "70"
3) "lisi"
4) "89"
5) "chenliu"
6) "99"

案例:如何利用zset实现一个文章访问量的排行榜?

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> zadd topn 1000 v1 2000 v2 800 v3 3000 v4 
(integer) 4
127.0.0.1:6379> zrevrange topn 0 -1 withscores
1) "v4"
2) "3000"
3) "v2"
4) "2000"
5) "v1"
6) "1000"
7) "v3"
8) "800"
数据结构

SortedSet(zset)是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构Map,可以给每一个元素value赋予一个权重score,另一方面它又类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。

zset底层使用了两个数据结构

(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。

(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。

使用场景

1、可以用于一个大型在线游戏的积分排行榜。每当玩家的分数发生变化时,可以执行ZADD命令更新玩家的分数,此后再通过ZRANGE命令获取积分TOPTEN的用户信息。当然我们也可以利用ZRANK命令通过username来获取玩家的排行信息。最后我们将组合使用ZRANGE和ZRANK命令快速的获取和某个玩家积分相近的其他用户的信息。

  1. Sorted-Set类型还可用于构建索引数据。
跳跃表(跳表) 简介

​ 有序集合在生活中比较常见,例如根据成绩对学生排名,根据得分对玩家排名等。对于有序集合的底层实现,可以用数组、平衡树、链表等。数组不便元素的插入、

删除;平衡树或红黑树虽然效率高但结构复杂;链表查询需要遍历所有效率低。Redis采用的是跳跃表。跳跃表效率堪比红黑树,实现远比红黑树简单。

实例

对比有序链表和跳跃表,从链表中查询出51

(1) 有序链表

image-20211027232218085

要查找值为51的元素,需要从第一个元素开始依次查找、比较才能找到。共需要6次比较。

(2) 跳跃表

image-20211027232229639

从第2层开始,1节点比51节点小,向后比较。

21节点比51节点小,继续向后比较,后面就是NULL了,所以从21节点向下到第1层

在第1层,41节点比51节点小,继续向后,61节点比51节点大,所以从41向下

在第0层,51节点为要查找的节点,节点被找到,共查找4次。

从此可以看出跳跃表比有序链表效率要高

关注
打赏
1638062488
查看更多评论
立即登录/注册

微信扫码登录

0.0610s