Redis笔记 ——String (用位图统计一段时间内用户登录天数,与网站指定时间段内活跃用户数)

  1. redis是一个高性能的 key-value 数据库,是跨平台的非关系型数据库
  2. redis基于内存,并且支持持久化。可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  3. redis支持的数据类型丰富,包括key-value类型数据,字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets)等
  4. redis的key值是二进制安全的,也就说可以用任何二进制序列作为key值,从简单字符串到一个图片文件都可以。
    (1)key的取值不能太长,太长消耗内容,而且查找键值成本太高
    (2)key值也不能太短,太短会导致看不懂键的含义
  5. Redis的所有操作都是原子性的,要么全部成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。

更多概念可以看菜鸟教程的 redis 部分

启动redis
方式一

进入redis安装目录的bin目录下面 nohup redis-server redis.conf &
按 ctrl + c 退出,然后再输入 redis-cli
在这里插入图片描述

方式二

打开两个终端,第一个终端进入bin目录下,输入 ./redis-server 启动服务端
第二个终端进入bin目录,输入 ./redis-cli 启动客户端,在客户端输入命令
在这里插入图片描述
在这里插入图片描述

启动完redis后,可以下载软件工具,使用可视化界面
在这里插入图片描述

String

新增,获取,更改
127.0.0.1:6379> set a abc //新增
OK
127.0.0.1:6379> get a   //获取
"abc"
127.0.0.1:6379> set a xyz  //更改,用新的值覆盖原先的值
OK
127.0.0.1:6379> get a
"xyz"
批量插入,批量获取
127.0.0.1:6379> mset b bb c cc  //mset批量插入
OK
127.0.0.1:6379> mget b c  //mget批量获取
1) "bb"
2) "cc"
设置过期时间

EX —— 秒
PX —— 毫秒
Redis中可以给Key设置一个生存时间(秒或毫秒),当达到这个时长后,这些键值将会被自动删除

(1)创建键值的时候设置过期时间

127.0.0.1:6379> set a a EX 5  //新增键值a a,并给这个键值设置5秒后过期
OK
127.0.0.1:6379> get a  //5秒内获取
"a"
127.0.0.1:6379> get a  //5秒后获取
(nil)

(2)给已经存在的key设置过期时间
格式:
EXPIRE key seconds
PEXPIRE key milliseconds

127.0.0.1:6379> expire b 5  
(integer) 1
127.0.0.1:6379> get b  //5s内获取
"bb"
127.0.0.1:6379> get b  //5s后获取
(nil)

(3)设置在指定的时间戳 过期
EXPIREAT key timestamp
PEXPIREAT key milliseconds-timestamp

127.0.0.1:6379> expireat c 1636974900 //2021-11-15 19:15:00的时间戳
(integer) 1
127.0.0.1:6379> get c  
"cc"
127.0.0.1:6379> get c
(nil)

(4)查看剩余时间
key存在但没有设置TTL,返回-1
key存在,但还在生存期内,返回剩余的秒或者毫秒
key曾经存在,但已经消亡,返回-2(2.8版本之前返回-1)

127.0.0.1:6379> expire k 5
(integer) 1
127.0.0.1:6379> ttl k  //还剩3s过期
(integer) 3
127.0.0.1:6379> ttl k
(integer) -2

查找key

keys 后面加上一个正则表达式,即可找到指定的key
keys * 任意长度字符
keys ? 任意一个字符
keys [] 字符集合,表示可以是集合中的任意一个

127.0.0.1:6379> keys *
1) "c"
2) "bb"
3) "a"
127.0.0.1:6379> keys ?
1) "c"
2) "a"
127.0.0.1:6379> keys ??
1) "bb"
127.0.0.1:6379> keys b?
1) "bb"
127.0.0.1:6379> keys [ac]
1) "c"
2) "a"
key的类型,key是否存在,key重命名,key删除

redis中
运行结果正确返回 (integer) 1
运行结果错误返回 (integer) 0

127.0.0.1:6379> type a  //判断类型
string
127.0.0.1:6379> exists a  //判断是否存在
(integer) 1
127.0.0.1:6379> exists aa
(integer) 0
127.0.0.1:6379> rename a aa  //重命名
OK
127.0.0.1:6379> exists aa
(integer) 1
127.0.0.1:6379> del aa  //删除
(integer) 1

方法
  • getset key value 返回旧值并设置新值。如果键不存在,就创建并赋值
  • strset key 获取指定key的value值长度
  • append key value 将新value内容追加到原先value值的后面,如果键存在就追加,如果不存在就等同于set key value
  • getrange key start end 截取子字符串,左闭右闭,【start,end】
    索引值从0开始,负数表示从字符串右边向左数起,-1表示最后的一个字符
  • setrange key offset value 从offset处,将value值覆盖在原先对应位置的字符串内容上
127.0.0.1:6379> getset c abc //	getset				 
"cc"                         
127.0.0.1:6379> strlen c  //获取字符串长度
(integer) 3
127.0.0.1:6379> append c xyz 
(integer) 6                  
127.0.0.1:6379> get c
"abcxyz"
127.0.0.1:6379> getrange c 1 3  //获取子字符串
"bcx"
127.0.0.1:6379> setrange c 1 1234  //覆盖部分字符串
(integer) 6
127.0.0.1:6379> get c
"a1234z"

步长的加减

虽然key和value都是字符串,但是value字符串里面要是数字的形式才能加减步长

127.0.0.1:6379> set a 10
OK
127.0.0.1:6379> incr a  //增加一个步长,value值加一
(integer) 11
127.0.0.1:6379> decr a  //减少一个步长,value值减一
(integer) 10
127.0.0.1:6379> incrby a 10  //增加指定的步长距离
(integer) 20
127.0.0.1:6379> decrby a 10  //减少指定的步长距离
(integer) 10

位图

位图不是真正的数据类型,只是在字符串类型中出现
一个字符串类型的值最多能存储512M字节的内容,1M等于1024k,1k等于1024byte,而1byte等于8bit,因此一个字符串类型的值最多有512x1024x1024x8位
比如现在存储了一个字符串 “ a ”,那么这个字符串的位图是
在这里插入图片描述
前面八位存放的是“ a ”的八位二进制,后面放着的512x1024x1024x8 - 8 位都是 0
在redis里面只有 1 才算数据占用内容,0是不占用内容的,所有即使有这么多的 0 也不会多占用内容
我们可以命令行中通过方法,来获取“ a ”的指定偏移量的位的内容

  1. setbit key offset value —— 设置某一位上的值
    (1)offset偏移量,从0开始
    (2)value不写,默认是0
    (3)当key不存在时,会自动创建一个key
  2. getbit key offset —— 获取指定偏移量对应的位置上的数值,0或1
127.0.0.1:6379> set k a
OK

127.0.0.1:6379> getbit k 0 
(integer) 0
127.0.0.1:6379> getbit k 1
(integer) 1
127.0.0.1:6379> getbit k 2
(integer) 1
127.0.0.1:6379> getbit k 3
(integer) 0
127.0.0.1:6379> getbit k 4
(integer) 0
127.0.0.1:6379> getbit k 5
(integer) 0
127.0.0.1:6379> getbit k 6
(integer) 0
127.0.0.1:6379> getbit k 7
(integer) 1

查询到的结果是0110 0001 ,正是 a 的ASCII码值 97 对应的二进制数

既然可以这样查询到二进制内容,也可以通过修改对应的位的二进制数字,从而修改value值

127.0.0.1:6379> setbit k 6 1  //将value值的第6位修改为1
(integer) 0
127.0.0.1:6379> setbit k 7 0  //将value值的第6位修改为0
(integer) 1
127.0.0.1:6379> get k
"b"

修改过后,二进制内容变为 0110 0010 也就是 97 即字符串 ” b “

当字符串里面不止有一个字符时,比如value值为 ” ab “,那么其位图的前十六位就是 a 和 b 的八位二进制数拼接而成
也就是 0110 0001 0110 0010

  1. bitcount
    BITCOUNT key 计算给定字符串中,被设置为 1 的比特位的数量
127.0.0.1:6379> bitcount k
(integer) 3  //0110 0001 里面一共有3个1

//可以给定区间,不过这个区间是用来划分几个字符在一个区间内
127.0.0.1:6379> set a aaaaaaaa
OK
127.0.0.1:6379> bitcount a //一个a有3个1,8个a一共24个1
(integer) 24
127.0.0.1:6379> bitcount a 0 3 // 这里的区间0 3是选中第0到第3个字符a,一共有4个a,所以12个1
(integer) 12
127.0.0.1:6379> bitcount a 0 7
(integer) 24

  1. bitpos
    BITPOS key bit [ start ] [ end ] 返回位图中第一个值为 bit 的二进制位的位置
127.0.0.1:6379> bitpos k 1 
(integer) 1   //0110 0001 里面1的第一次出现的位置是索引1位置
  1. bitop
    BITOP operation destkey key [key …] 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上
    operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种

AND —— 逻辑并 —— 1 and 1=1,1 and 0= 0,0 and 0= 0,0 and 1= 0
OR —— 或运算 —— 1 or 1= 1,1 or 0= 1,0 or 0= 0,0 or 1= 1
NOT —— 逻辑非 —— not 1 = 0,not 0 = 1
XOR —— 异或运算 —— 相同为0,不同为1

利用位图来统计用户登录天数

将用户id作为键值对的key值,后面的value值是一个String字符串,字符串内有一个位图
将位图的偏移量作为第几天,将对应位置的 1 表示已登录,0 表示未登录
在这里插入图片描述
这样用bitcount统计每个key值中的 1 的数量,即可统计用户登录天数
而第一天是指位图的偏移量 0,也就是第 0 位

//用户id为1001,设置第一天已登录,也就是设置偏移量为0的位置上值为1
127.0.0.1:6379> setbit 1001 0 1 
(integer) 0
127.0.0.1:6379> setbit 1001 3 1
(integer) 0
127.0.0.1:6379> setbit 1001 5 1
(integer) 0
127.0.0.1:6379> setbit 1001 7 1
(integer) 0
127.0.0.1:6379> setbit 1001 12 1
(integer) 0
127.0.0.1:6379> bitcount 1001  //用户1001一共登录了5天
(integer) 5

这样只能统计某个用户的全部登录次数,那么如果想给定一个时间段,然后统计该时间段内的登录次数该怎么做?
之前说过,如果直接在bitcount后面给一个区间,那么是将几个字符包含在一起,也就是说

redis 的 setbit 修改的是 bit 位置,而 bitcount 检查的是 byte 位置,两者相差有 8 的倍数。

因此如果想求取第9天到第16天的全部登录次数的话,可以这样统计

127.0.0.1:6379> bitcount 1001 1 1
(integer) 1
127.0.0.1:6379> setbit 1001 14 1 
(integer) 0
127.0.0.1:6379> setbit 1001 15 1 //在第16天用户也登录了
(integer) 0
127.0.0.1:6379> bitcount 1001 1 1  //第八天到第十六天一共登录了3次
(integer) 3
按天统计网站当天的活跃用户

以某一天作为key,然后以字符串为value值,字符串里面的位图中,偏移量代表用户id,位值表示是否登录
假设2月1号,有1001,1002,1003三位用户登录网站
2月2号有 1001,1002,1005 三位用户登录网站,现在要统计2月1号到2月2号的所有登录网站的用户数量
在这里插入图片描述
思路就是利用 OR 运算计算2月1号和2月2号的位图里的值,然后统计2月1号-2月2号的位图里面的 1 的数量

127.0.0.1:6379> setbit 02-01 1001 1
(integer) 0
127.0.0.1:6379> setbit 02-01 1002 1
(integer) 0
127.0.0.1:6379> setbit 02-01 1003 1
(integer) 0
127.0.0.1:6379> setbit 02-02 1001 1
(integer) 0
127.0.0.1:6379> setbit 02-02 1002 1
(integer) 0
127.0.0.1:6379> setbit 02-02 1005 1
(integer) 0
127.0.0.1:6379> bitop or 02-01~02-02 02-01 02-02
(integer) 126
127.0.0.1:6379> bitcount 02-01~02-02
(integer) 4

最后统计的结果为4,2月1号到2月2号期间,一共有4位用户登录了网站

同样的,这种思路也可以用于求取,两个用户的共同关注
比如张同学关注了用户 001,002,004
然后陈同学关注了用户 001,003,004
那么两个位图的值分别是,1101 和 1011,用 and 对两个数进行运算,结果为 1001
两人的共同关注是 001 和 004

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一纸春秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值