6. set集合
集合:把一些有关联的数据放在一起。
1、集合中的元素是无序的,即数据存放顺序不重要,变化一下顺序,集合依旧是之前的集合。
2、集合中的元素是不能重复的(唯一性)与list类似的是集合中的每一个元素也都是string类型的,可以使用json格式的字符串存储结构化数据。
6.1 set指令
SADD : 将⼀个或者多个元素添加到set中,重复的元素⽆法添加到set中。
SADD key member [member ...]
时间复杂度:O(1)
返回值:本次添加成功的元素个数。
SMEMBERS 获取⼀个set中的所有元素,元素间的顺序是⽆序的。
SMEMBERS key
时间复杂度:O(N)
返回值:所有元素的列表。
SISMEMBER :判断⼀个元素在不在set中。
SISMEMBER key member
时间复杂度:O(1)
返回值:1表⽰元素在set中。0表⽰元素不在set中或者key不存在。
spop:随机删除一个或多个元素。
SPOP key [count]
时间复杂度:O(N),n是count
返回值:取出的元素。
SMOVE 将⼀个元素从源set取出并放⼊⽬标set中。
SMOVE source destination member
时间复杂度:O(1)
返回值:1表⽰移动成功,0表⽰失败。
srem:将指定的元素从set中删除。
SREM key member [member ...]
时间复杂度:O(N),N是要删除的元素个数.
返回值:本次操作删除的元素个数。
6.2 集合间的操作
交集(inter)、并集(union)、差集(diff)的概念如图所⽰。
SINTER:给定set的交集中的元素。
SINTER key [key ...]
时间复杂度:O(N*M),N是最⼩的集合元素个数.M是最⼤的集合元素个数.
返回值:交集的元素。
SINTERSTORE 获取给定set的交集中的元素并保存到⽬标set中。
SINTERSTORE destination key [key ...]
时间复杂度:O(N*M),N是最⼩的集合元素个数.M是最⼤的集合元素个数.
返回值:交集的元素个数。
SUNION 获取给定set的并集中的元素。
SUNION key [key ...]
时间复杂度:O(N),N给定的所有集合的总的元素个数.
返回值:并集的元素。
SUNIONSTORE 获取给定set的并集中的元素并保存到⽬标set中。
SUNIONSTORE destination key [key ...]
时间复杂度:O(N),N给定的所有集合的总的元素个数.
返回值:并集的元素个数。
SDIFF 获取给定set的差集中的元素。
SDIFF key [key ...]
时间复杂度:O(N),N给定的所有集合的总的元素个数.
返回值:差集的元素。
SDIFFSTORE 获取给定set的差集中的元素并保存到⽬标set中。
SDIFFSTORE destination key [key ...]
时间复杂度:O(N),N给定的所有集合的总的元素个数.
返回值:差集的元素个数。
6.3 内部编码
java中的set本质上是一个接口,其实现方式可以是treeset或hashset。
intset(整数集合):为了节省空间做的特定优化。当元素为整数,且元素的个数不是很多的时候。
hashtable(哈希表):当集合类型⽆法满⾜intset的条件时,Redis会使⽤hashtable作为集合 的内部实现。
6.4 set的应用场景
1、使用set来保存用户的标签
2、方便计算交集
3、使用set统计uv:
1、pv page view 用户每一次访问浏览器,都会产生一个pv。
2、uv user view 用户每一次访问浏览器,都会产生一个uv。但是同一个用户多次访问同一个页面只会增加一次uv。
7.zset 有序集合
zset排序的规则:给zset中的member引入一个属性分数(score,浮点类型),每一个member都会安排一个分数,进行排序的时候,就是按照次数的分数的大小进行升序或降序排的。zset中的member要求是唯一的,但是其score不是唯一的。
7.1 列表、集合、有序集合三者的异同点
7.2 操作指令
ZADD:添加或者更新指定的元素以及关联的分数到zset中,分数应该符合double类型,+inf/-inf作为正负 极限也是合法的。可以根据member来查找score,也可以通过score查找member。
ZADD的相关选项:
• XX:仅仅⽤于更新已经存在的元素,不会添加新元素。元素指的是member。
• NX:仅⽤于添加新元素,不会更新已经存在的元素。
• CH:默认情况下,ZADD返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次修改的元素的个数。
• INCR:此时命令类似ZINCRBY的效果,将元素的分数加上指定的分数。此时只能指定⼀个元素和 分数。
lt:less than 现在更新分数,给定的值要比之前的值分数小,就进行更新,负责不更新。
gt:greater than:只有分数数值大于之前的数值的时候才会进行更新。
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]
时间复杂度:O(log(N)),n是有序集合中已经存在的元素个数。由于zset是有序结构,在新增元素的时候要进行找位置。
返回值:本次添加成功的元素个数。
如果两个member的score是一样的话,就按照元素自身的字典序来排列。zset内部实际是按照升序排列的。
zrange:查看有序集合中的元素详情了,redis内部存储数据的时候,是按照二进制的方式来存储的,即redis服务器不负责"字符编码",要把二进制字节转回到汉字,就需要在客户端进行指令"redis-cli --raw"
查询带分数的值:zrange key 0 -1 withscores
ZRANGE :返回指定区间⾥的元素,分数按照升序。带上WITHSCORES可以把分数也返回。
ZRANGE key start stop [WITHSCORES] 处的[start, stop] 为下标构成的区间.从0开始,⽀持负数. 时间复杂度:O(log(N)+M),表示两个区间之间的元素的个数。
返回值:区间内的元素列表
ZCARD:获取⼀个zset的基数(cardinality),即zset中的元素个数。
ZCARD key
时间复杂度:O(1)
返回值:zset内的元素个数
ZCOUNT 返回分数在min和max之间的元素个数,默认情况下,min和max都是包含的,可以通过(排除。
ZCOUNT key min max
时间复杂度:O(log(N)),zset内部会记录每一个元素当前的排行,直接查询max和min元素,就知道了这两个元素的次序,然后做减法获取返回值。
返回值:满⾜条件的元素列表个数。
排除min值的语法:ZCOUNT key (min max,加一个括号。
排除max的语法:ZCOUNT key min (max,也加一个括号。
min和max可以写成浮点数,inf.表示无穷大,- inf.表示无穷大。
ZREVRANGE :返回指定区间⾥的元素,分数按照降序。带上WITHSCORES可以把分数也返回。
ZREVRANGE key start stop [WITHSCORES]
时间复杂度:O(log(N)+M)
返回值:区间内的元素列表。
语法中的-1,表示len-1.
ZRANGEBYSCORE:返回分数在min和max之间的元素,默认情况下,min和max都是包含的,可以通过(排除。
ZRANGEBYSCORE key min max [WITHSCORES]
时间复杂度:O(log(N)+M)
返回值:区间内的元素列表。
ZPOPMAX 删除并返回分数最⾼的count个元素。
ZPOPMAX key [count]
时间复杂度:O(log(N)*M)
返回值:分数和元素列表。
BZPOPMAX :ZPOPMAX的阻塞版本。每一个key都是一个有序集合。阻塞也是在有序集合为空的时候触发的阻塞,阻塞到有其他客户端插入元素。
BZPOPMAX key [key ...] timeout
时间复杂度:O(log(N))
返回值:元素列表。
当然如果有序集合中已经有了元素,就直接返回元素,不用进行阻塞了。如果当前bzpopmax同时监听了多个key,假设有m个key,此时的时间复杂度依旧是O(log(N))。
ZPOPMIN :删除并返回分数最低的count个元素。
ZPOPMIN key [count]
时间复杂度:O(log(N)*M)
返回值:分数和元素列表。
虽然redis的有序函数记录了开头的元素,但是删除的时候使用的是通用的删除函数,故此导致了重新查找的过程。
BZPOPMIN :ZPOPMIN的阻塞版本。
BZPOPMIN key [key ...] timeout
时间复杂度:O(log(N))
返回值:元素列表。
ZRANK :返回指定元素的排名(下标),升序的方式。
ZRANK key member
时间复杂度:O(log(N))
返回值:排名。
ZREVRANK :返回指定元素的排名,降序的方式。
ZREVRANK key member
时间复杂度:O(log(N))
返回值:排名。
ZSCORE 返回指定元素的分数。
ZSCORE key member
时间复杂度:O(1)
返回值:分数
此处相当于redis对于这样的查询操作做了特殊的优化,通过扩大空间的消耗面对与时间复杂度优化到了o(1)。
ZREM 删除指定的元素。
ZREM key member [member ...]
时间复杂度:O(M*log(N)),m是参数的个数
返回值:本次操作删除的元素个数。
ZREMRANGEBYRANK 按照排序,升序删除指定范围的元素,左闭右闭。
ZREMRANGEBYRANK key start stop
时间复杂度:O(log(N)+M)
返回值:本次操作删除的元素个数。
ZREMRANGEBYSCORE 按照分数删除指定范围的元素,左闭右闭。
ZREMRANGEBYSCORE key min max
时间复杂度:O(log(N)+M)
返回值:本次操作删除的元素个数。
ZINCRBY 为指定的元素的关联分数添加指定的分数值。
ZINCRBY key increment member
时间复杂度:O(log(N))
返回值:增加后元素的分数。
zinterstore:交集,结果保存到另一个key中。
zunionstore:并集,结果保存到另一个key中。
所谓权重就是每一个部分占整体的分量的比例。
aggregate:统计,合计。
在zset中,member才是元素本体,score只是辅助排序的工具人,因此在进行比较"相同"的时候,只要member相同即可,score不一样无所谓。但是求交集的时候相同元素不同score的最终score应该怎样计算。
计算规则按照aggregate的sum,max,min这三种方式进行计算。默认是sum的方式。
时间复杂度:o(n*k)+o(m*log(n)),n是输入若干个有序集合,里面元素最小的个数。k是吧k个有序集合求交集,m是最终结果的有序集合元素个数。近似来算可以看成
o(m*log(m))。
ZUNIONSTORE: 求并集
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <sum | max | min> ]
时间复杂度:O(N)+O(M*log(M)) N是输⼊的有序集合总的元素个数;M是最终结果的有序集合的元素 个数. 返回值:⽬标集合中的元素个数
7.3 内部编码
1、当元素个数较少且每个元素较⼩时,内部编码为ziplist:
2、当元素个数较多或者单个元素体积较大,内部编码skiplist:
7.4 zset的应用场景
1、排行榜系统
1m字节是百万级别,1g是十亿字节级别。
8. streams
事件:每次socket上都有可读可写的数据,都会通过事件回调机制来通知相关的应用程序代码。有些操作不知道啥时候出现,所以只能等事情出现之后再采取动作。
streams类似于一个阻塞队列。属于是list的blpop/brpop的升级版本。
9. geospatial
地理空间。用来存储坐标,存储一些点之后,根据用户给定的一个坐标和半径扫描,去查找redis中存储的符合条件的位置坐标。一般应用于地图中查找位置和定点范围内地点查询。
10. hyperloglog
应用场景只有一个,估算集合中的元素的个数。
使用set记录浏览器的uv,可以知道每一个uv的相关详细信息。但是需要消耗很大的空间资源。hyperloglog最多使用12kb的空间实现对于上亿次uv的数量统计,但是仅仅是统计数量,并不能知道每一个uv的访问信息。
但是该指令存在0.81%的估算误差。
11. bitmaps
位图:使用bit位来表示整数。本质上还是一个集合,属于是set类型针对整数的特化版本。bitmap相对于hyplerloglog,能够存储元素。
下面将10存储到位图中:
12. bitfields
位域,本质上是让我们进行精确进行位操作的一种方法。bitfields可以理解成一串二进制序列(字节数组),同时可以把这个字节数组的某几个位赋予特定的含义,进行一系列的相关操作。该效果相对于string和hash也是节省了大部分空间。
ps:谢谢观看!