Set作为一个没有重复元素的集合,可以应用的场景也很多。
Set类型常用操作
常用的操作是
SADD 向集合中添加元素
127.0.0.1:6379> SADD day user1
(integer) 1
127.0.0.1:6379> SADD day user2
(integer) 1
SCARD 返回集合中元素的个数
127.0.0.1:6379> SCARD day
(integer) 2
SPOP 从集合中随机返回一个并删除
127.0.0.1:6379> SPOP day
"user2"
SREM 删除集合中指定元素
127.0.0.1:6379> REM day user1
(integer) 1
127.0.0.1:6379> SREM day user3 # 删除不存在的元素返回0
(integer) 0
SDIFF 两个集合之间的差异
127.0.0.1:6379> SADD day1 user1 user2 user3 user4
(integer) 4
127.0.0.1:6379> SADD day2 user2 user3 user5
(integer) 3
127.0.0.1:6379> SDIFF day2 day1
1) "user5"
127.0.0.1:6379> SDIFFSTORE day:diff day2 day1 #day1 和 day2的差集存入新的集合中
(integer) 1
127.0.0.1:6379> SCARD day:diff
(integer) 1
类似的还有交集 和并集
SINTER SINTERSTORE
SUNION SUNIONSTORE
实际应用场景
1.统计UV
统计某个应用/页面一天的UV
UV的特点是只要记录过一次,后面继续记录不能重复,首先可以将每一天记录为一个集合的key
127.0.0.1:6379> SADD day:uv:app:20240520 u1 # 可以是用户id 也可以是独立IP 具体看业务
(integer) 1
127.0.0.1:6379> SADD day:uv:app:20240520 u2
(integer) 1
127.0.0.1:6379> SADD day:uv:app:20240520 u3
(integer) 1
一天结束后使用SCARD统计总数
127.0.0.1:6379> SCARD day:uv:app:20240520
(integer) 3
每次统计结束后可以将每天的UV数据转存到其他数据库,并定时清理掉很久之间的集合数据,释放内存。
2.新增用户统计
每日新增用户,统计每天新增的用户
准备一个所有用户ID的集合,然后每天再准备一个当天使用的用户ID集合;
比如第一天有3个用户进入应用
127.0.0.1:6379> SADD day:app:20240520 u1
(integer) 1
127.0.0.1:6379> SADD day:app:20240520 u2
(integer) 1
127.0.0.1:6379> SADD day:app:20240520 u3
(integer) 1
第一天结束后将第一天的数据合并写入所有用户集合中
127.0.0.1:6379> SUNIONSTORE day:app day:app day:app:20240520
(integer) 3
第二天继续统计进入系统的用户
127.0.0.1:6379> SADD day:app:20240521 u3
(integer) 1
127.0.0.1:6379> SADD day:app:20240521 u4
(integer) 1
127.0.0.1:6379> SADD day:app:20240521 u5
(integer) 1
结束后,先计算差集, 获得新增用户名单
127.0.0.1:6379> SDIFF day:app:20240521 day:app
1) "u4"
2) "u5"
如果只是想获得新增数量 也可以先用SDIFFSTORE 将差集计算出来,再使用SCARD获取数量
127.0.0.1:6379> SDIFFSTORE day:app:20240521_day:app day:app:20240521 day:app
(integer) 2
127.0.0.1:6379> SCARD day:app:20240521_day:app
(integer) 2
最后再将第二天的合并进入所有用户的集合中
127.0.0.1:6379> SUNIONSTORE day:app day:app day:app:20240521
(integer) 5
当然也可以使用SINTER 返回老用户名单
需要注意的事,如果集合元素非常多,不建议直接用Redis进行聚合计算,因为集合的聚合计算复杂度较高,对于Redis这种单线程执行的服务来说,会阻塞其他客户端的请求,可以将数据取出放到客户端上去计算。
3.随机抽奖
随机抽奖就比较简单了,就是基于SRANDMEMBER随机从集合中返回指定个数的元素
写入待抽奖的编号
127.0.0.1:6379> SADD rewards u1 u2 u3 u4 u5 u6 u7 u8 u9 u10
(integer) 10
随机返回指定个数的元素
127.0.0.1:6379> SRANDMEMBER rewards 2
1) "u8"
2) "u2"
127.0.0.1:6379> SRANDMEMBER rewards 2
1) "u4"
2) "u1"
127.0.0.1:6379> SRANDMEMBER rewards 3
1) "u4"
2) "u7"
3) "u6"