【Redis】Set集合、Zset有序集合以及其它数据类型

文章目录

  • [1. Set](#1. Set)
    • [1.1 常用命令](#1.1 常用命令)
    • [1.2 集合间操作](#1.2 集合间操作)
    • [1.3 内部编码](#1.3 内部编码)
    • [1.4 使用场景](#1.4 使用场景)
  • [2. Zset 有序集合](#2. Zset 有序集合)
    • [2.1 常用命令](#2.1 常用命令)
    • [2.2 内部编码](#2.2 内部编码)
    • [2.3 应用场景](#2.3 应用场景)
  • [3. 其它数据类型](#3. 其它数据类型)
    • [3.1 stream](#3.1 stream)
    • [3.2 geospatial](#3.2 geospatial)
    • [3.3 HyperLogLog](#3.3 HyperLogLog)
    • [3.4 bitmap](#3.4 bitmap)
    • [3.5 bitfield](#3.5 bitfield)
  • [4. 渐进式遍历](#4. 渐进式遍历)
  • [5. 数据库管理](#5. 数据库管理)

1. Set

集合类型也是保存多个字符串类型的元素的,但和列表类型不同的是,集合中元素之间是⽆序的,元素不允许重复,⼀个集合中最多可以存储232-1个元素。

Redis除了⽀持集合内的增删查改操作,同时还⽀持多个集合取交集、并集、差集,合理地使⽤好集合类型,能在实际开发中解决很多问题。

1.1 常用命令

  1. sadd:将⼀个或者多个元素添加到set中(重复的元素⽆法添加到set中)
bash 复制代码
SADD key member [member ...]
  1. smembers:获取⼀个set中的所有元素(元素间的顺序是⽆序的)
bash 复制代码
SMEMBERS key
  1. sismember:判断⼀个元素在不在set中
bash 复制代码
SISMEMBER key member
  1. SCARD:获取⼀个set的基数(cardinality),即set中的元素个数
bash 复制代码
SCARD key
  1. spop:从set中删除并返回⼀个或者多个元素(由于set内的元素是无序的,所以取出哪个元素实际是未定义行为,即可以看作随机的)
bash 复制代码
SPOP key [count]
  1. smove:将⼀个元素从源set取出并放⼊⽬标set中
bash 复制代码
smove source destination member
  1. srem:将指定的元素从set中删除
bash 复制代码
srem key member [member ...]

1.2 集合间操作

交集(inter)、并集(union)、差集(diff)的概念如图所示:

  1. sinter:获取给定set的交集中的元素
bash 复制代码
SINTER key [key ...]
  1. SINTERSTORE:获取给定set的交集中的元素并保存到⽬标set中
bash 复制代码
SINTERSTORE destination key [key ...]
  1. SUNION:获取给定set的并集中的元素
bash 复制代码
SUNION key [key ...]
  1. SUNIONSTORE:获取给定set的并集中的元素并保存到⽬标set中
bash 复制代码
SUNIONSTORE destination key [key ...]
  1. SDIFF:获取给定set的差集中的元素
bash 复制代码
SDIFF key [key ...]
  1. SDIFFSTORE:获取给定set的差集中的元素并保存到⽬标set中
bash 复制代码
SDIFFSTORE destination key [key ...]

命令小节:

1.3 内部编码

集合类型的内部编码有两种:

  • intset(整数集合):当集合中的元素都是整数并且元素的个数小于set-max-intset-entries配置(默认512个)时,Redis会选⽤intset来作为集合的内部实现,从⽽减少内存的使用。
  • hashtable(哈希表):当集合类型⽆法满⾜intset的条件时,Redis会使⽤hashtable作为集合的内部实现
  1. 当元素个数较少并且都为整数时,内部编码为intset
bash 复制代码
127.0.0.1:6379> sadd setkey 1 2 3 4
(integer) 4
127.0.0.1:6379> object encoding setkey
"intset"
  1. 当元素个数超过512个,内部编码为hashtable
bash 复制代码
127.0.0.1:6379> sadd setkey 1 2 3 4 ... 513
(integer) 513
127.0.0.1:6379> object encoding setkey
"hashtable"
  1. 当存在元素不是整数时,内部编码为hashtable
bash 复制代码
127.0.0.1:6379> sadd setkey a
(integer) 1
127.0.0.1:6379> object encoding setkey
"hashtable"

1.4 使用场景

集合类型比较典型的使⽤场景是标签(tag)

  • 例如A用户对娱乐、体育板块⽐较感兴趣;B用户对历史、新闻⽐较感兴趣,这些兴趣点可以被抽象为标签。
  • 有了这些数据就可以得到喜欢同⼀个标签的⼈,以及用户的共同喜好的标签,这些数据对于增强用户体验和用户黏度都⾮常有帮助。例如⼀个电⼦商务⽹站会对不同标签的用户做不同的产品推荐

下⾯的演⽰通过集合类型来实现标签的若⼲功能

  1. 给用户添加标签
bash 复制代码
sadd user:1:tags tag1 tag2 tag5
sadd user:2:tags tag2 tag3 tag5
...
sadd user:k:tags tag1 tag2 tag4
  1. 给标签添加用户
bash 复制代码
sadd tag1:users user:1 user:3
sadd tag2:users user:1 user:2 user:3
...
sadd tagk:users user:1 user:4 user:9 user:28
  1. 计算用户的共同兴趣标签
bash 复制代码
sinter user:1:tags user:2:tags

2. Zset 有序集合

有序集合相对于字符串、列表、哈希、集合来说会有⼀些陌生

它保留了集合不能有重复成员的特点,但与集合不同的是,有序集合中的每个元素都有⼀个唯⼀的浮点类型的分数(score)与之关联 ,这使得有序集合中的元素是可以维护有序性的,但这个有序不是用下标作为排序依据而是用这个分数

有序集合中的元素是不能重复的,但分数允许重复;分数相同,则按元素字典序排序

有序集合提供了获取指定分数和元素范围查找、计算成员排名等功能,合理地利用有序集合,可以帮助我们在实际开发中解决很多问题。

2.1 常用命令

  1. zadd:添加或者更新指定的元素以及关联的分数到zset中,分数应该符合double类型,+inf/-inf作为正负极限也是合法的
bash 复制代码
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member...]

默认情况下,ZADD返回的是本次添加的元素个数

相关选项:

  • XX:仅仅⽤于更新已经存在的元素,不会添加新元素。
  • NX:仅⽤于添加新元素,不会更新已经存在的元素。
  • CH:默认情况下,ZADD返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次更新的元素的个数。
  • INCR:此时命令类似ZINCRBY的效果,将元素的分数加上指定的分数。此时只能指定⼀个元素和分数。
  • LT:仅当新分数小于(lesser)当前分数时,才更新现有元素。此标志不会阻止添加新元素。
  • GT:仅当新分数大于(greater)当前分数时,才更新现有元素。此标志不会阻止添加新元素
    • GT、LT是Redis 6.2.0 版本开始引入的

GT、LT 和 NX 选项是互斥的

  1. ZRANGE:返回指定区间⾥的元素,分数按照升序。带上WITHSCORES可以把分数也返回
bash 复制代码
ZRANGE key start stop [WITHSCORES]

此处的[start, stop] 为下标构成的区间从0开始,⽀持负数

  1. zcard:获取⼀个zset的基数(cardinality),即zset中的元素个数
bash 复制代码
ZCARD key
  1. zcount:返回分数在min和max之间的元素个数,默认情况下,min和max都是包含的,可以通过(排除
bash 复制代码
ZCOUNT key min max
  1. ZREVRANGE:返回指定区间⾥的元素,分数按照降序。带上WITHSCORES可以把分数也返回

备注:这个命令可能在6.2.0之后废弃,并且功能合并到ZRANGE中

bash 复制代码
ZREVRANGE key start stop [WITHSCORES]
  1. ZRANGEBYSCORE:返回分数在min和max之间的元素 ,默认情况下,min和max都是包含的,可以通过(排除。

备注:这个命令可能在6.2.0之后废弃,并且功能合并到ZRANGE中

bash 复制代码
ZRANGEBYSCORE key min max [WITHSCORES]
  1. ZPOPMAX:删除并返回分数最⾼的count个元素。
bash 复制代码
ZPOPMAX key [count]
  1. BZPOPMAX: ZPOPMAX的阻塞版本
bash 复制代码
 BZPOPMAX key [key ...] timeout
  1. ZPOPMIN:删除并返回分数最低的count个元素
bash 复制代码
ZPOPMIN key [count]
  1. BZPOPMIN: ZPOPMIN的阻塞版本
bash 复制代码
BZPOPMIN key [key ...] timeout
  1. ZRANK:返回指定元素的排名,升序。
bash 复制代码
ZRANK key member
  1. ZREVRANK:返回指定元素的排名,降序
bash 复制代码
ZREVRANK key member
  1. ZSCORE:返回指定元素的分数
bash 复制代码
ZSCORE key member
  1. ZREM:删除指定的元素
bash 复制代码
ZREM key member [member ...]
  1. ZREMRANGEBYRANK:按照排序,升序删除指定范围的元素,左闭右闭
bash 复制代码
ZREMRANGEBYRANK key start stop
  1. ZREMRANGEBYSCORE:按照分数删除指定范围的元素,左闭右闭
bash 复制代码
ZREMRANGEBYSCORE key min max
  1. ZINCRBY:为指定的元素的关联分数添加指定的分数值
bash 复制代码
ZINCRBY key increment member

集合间操作

  1. ZINTERSTORE:求出给定有序集合中元素的交集并保存进⽬标有序集合中,在合并过程中以元素为单位进⾏合并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数
bash 复制代码
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] 
[AGGREGATE <SUM | MIN | MAX>]
  • numkeys:有几个key参与运算,为了与后面的选项区分
  • weights:权重,表示所参与交集运算key的重要性,会乘以当前的分数
  • aggregate:聚合方式


  1. ZUNIONSTORE:求出给定有序集合中元素的并集并保存进⽬标有序集合中,在合并过程中以元素为单位进⾏合并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数
bash 复制代码
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] 
[AGGREGATE <SUM | MIN | MAX>]

命令小节:

2.2 内部编码

有序集合类型的内部编码有两种:

  • ziplist(压缩列表):当有序集合的元素个数⼩于zset-max-ziplist-entries配置(默认128个),同时每个元素的值都⼩于zset-max-ziplist-value配置(默认64字节)时,Redis会⽤ziplist来作为有序集合的内部实现,ziplist可以有效减少内存的使⽤。
  • skiplist(跳表):当ziplist条件不满⾜时,有序集合会使⽤skiplist作为内部实现,因为此时ziplist的操作效率会下降

2.3 应用场景

有序集合⽐较典型的使⽤场景就是排⾏榜系统。例如常⻅的⽹站上的热榜信息,榜单的维度可能是多方面的:按照时间、按照阅读量、按照点赞量。

本例中我们使⽤点赞数这个维度,维护每天的热榜:

  1. 添加用户赞数

例如用户james发布了⼀篇⽂章,并获得3个赞,可以使⽤有序集合的zadd和zincrby功能:

bash 复制代码
zadd user:ranking:2022-03-15 3 james

之后如果再获得赞,可以使⽤zincrby:

bash 复制代码
zincrby user:ranking:2022-03-15 1 jame
  1. 取消用户赞数

由于各种原因(例如⽤⼾注销、⽤⼾作弊等)需要将⽤⼾删除,此时需要将⽤⼾从榜单中删除掉,可以使⽤zrem。例如删除成员tom:

bash 复制代码
zrem user:ranking:2022-03-15 tom
  1. 展示获取赞数最多的10个用户

此功能使⽤zrevrange命令实现:

bash 复制代码
 zrevrangebyrank user:ranking:2022-03-15 0 9
  1. 展示用户信息以及用户分数

此功能将用户名作为键后缀,将用户信息保存在哈希类型中,⾄于用户的分数和排名可以使⽤zscore和zrank来实现。


列表、集合、有序集合三者的异同点

3. 其它数据类型

在前面,我们已经了解了Redis的五个常用类型:String、list、hash、set、zset。

除此之外,Redis还提供了一些其它的类型

3.1 stream

Stream是一种数据结构,其作用类似于仅追加日志,但也实施了多项操作来克服典型仅追加日志的一些限制。其中包括 O(1) 时间的随机访问和复杂的消费策略。

通俗来讲就是:stream类型,可以用来模拟实现时间传播的机制,本质就是一个队列(redis作为消息队列的根本),比list、blpop、brpop功能更加强大。

3.2 geospatial

地理索引允许您存储坐标并进行搜索。 此数据结构可用于查找给定半径或边界框内的附近点

3.3 HyperLogLog

HyperLogLog 是一种概率数据结构,用于估计集合重元素的个数

HyperLogLog 以完美的准确性换取了高效的空间利用。

Redis HyperLogLog 实现最多使用 12 KB,并提供0.81% 的标准误差。

我们知道set有一个应用场景:统计服务器的用户访问次数(UV)。

当然使用set也可以很好的统计,但是当这个数据量比较大时,set会消耗很多的内存空间。

假设set存uid,每个uid按8字节算,如果有1亿的UV--> 8亿字节-->800M;但是使用hyperloglog最多使用12KB空间

Hyperloglog不存储元素的内容,但是能够记录元素的特征,从而在新增元素的时候,能够知道当前新增的元素,是新增的元素,还是已经存在的元素。 所以可以用来计数,但是无法告诉你元素是什么。

3.4 bitmap

位图

3.5 bitfield

位域

bitfield可以理解为一串二进制序列(字节数组),同时可以把这个字节数组的某几个位,赋予特定的含义,并且进行读取、修改、算术等相关操作

4. 渐进式遍历

在前面,我们学习了keys命令,它可以获取key,但是该命令有时候是非常危险的,可能会阻塞redis服务器

渐进式遍历(SCAN)不会阻塞redis服务器,它执行一次命令,只获取其中的一小部分,要想获取所有的key,就需要执行多次渐进式遍历命令

bash 复制代码
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]

首次scan从0开始,当scan返回的下次位置为0时,遍历结束

  • cursor:指向开始遍历的位置,不能理解成下标,它仅是个字符串
  • count:遍历的个数(实际返回的个数不一定完全相同),默认是10
  • pattern:匹配的规则,跟keys相同
  • type:指明要获取key的value的类型
  • 返回值
    • 下次开始遍历的位置
    • 此次遍历的结果

除了scan以外,Redis⾯向哈希类型、集合类型、有序集合类型分别提供了hscan、sscan、zscan命令,它们的⽤法和scan基本类似

渐进性遍历scan虽然解决了阻塞的问题,但如果在遍历期间键有所变化(增加、修改、删除),可能导致遍历时键的重复遍历或者遗漏,这点务必在实际开发中考虑。

5. 数据库管理

redis提供了16个数据库,编号位0-15 ,默认使用0号,用户无法创建和删除

Redis 提供了⼏个⾯向Redis数据库的操作,分别是dbsize、select、flushdb、flushall命令,本机将通过具体的使⽤常⻅介绍这些命令。

  1. select:切换数据库
  1. dbsize:获取当前数据库中key的个数

  2. flushdb:删除当前库中的key

  3. flushall:删除所有库中所有的key

相关推荐
带刺的坐椅20 分钟前
Solon v3.4.7, v3.5.6, v3.6.1 发布(国产优秀应用开发框架)
java·spring·solon
四谎真好看2 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
桦说编程2 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t2 小时前
ZIP工具类
java·zip
lang201509282 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
pengzhuofan3 小时前
第10章 Maven
java·maven
百锦再4 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
刘一说4 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多4 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring
百锦再4 小时前
对前后端分离与前后端不分离(通常指服务端渲染)的架构进行全方位的对比分析
java·开发语言·python·架构·eclipse·php·maven