redis位图命令

概述

redis 的位图就是01的数据格式,redis 主要做有写入,读取和统计。位图相关的命令 :

redis位图命令

其中set和get就是 read 和writer , bitcount 统计相关,bitop 是对bit进行操作01的,bitpos 获取某个范围内第一个值为 bit 的位置;bitfield 则是批量操作的命令

例子

写入的过程如下,以下是一个例子(来自参考资料)

redis位图命令

127.0.0.1:6379> setbit s 1 1
(integer) 0
127.0.0.1:6379> setbit s 2 1
(integer) 0
127.0.0.1:6379> setbit s 4 1
(integer) 0
127.0.0.1:6379> setbit s 9 1
(integer) 0
127.0.0.1:6379> setbit s 10 1
(integer) 0
127.0.0.1:6379> setbit s 13 1
(integer) 0
127.0.0.1:6379> setbit s 15 1
(integer) 0
127.0.0.1:6379> get s
"he"

read 和 write

127.0.0.1:6379> setbit w 1 1
(integer) 0
127.0.0.1:6379> getbit w 2
(integer) 1

统计和查找

统计和查找用到两个命令。

  • bitcount : bitcount 用来统计指定位置范围内 1 的个数
  • bitpos : 用来查找指定范围内出现的第一个 0 或 1,命令格式 : bitpos key bit [start] [end]

例子来自于参考资料

127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitcount w
(integer) 21
127.0.0.1:6379> bitcount w 0 0 # 第一个字符中 1 的位数
(integer) 3
127.0.0.1:6379> bitcount w 0 1 # 前两个字符中 1 的位数
(integer) 7
127.0.0.1:6379> bitpos w 0 # 第一个 0 位
(integer) 0
127.0.0.1:6379> bitpos w 1 # 第一个 1 位
(integer) 1
127.0.0.1:6379> bitpos w 1 1 1 # 从第二个字符算起,第一个 1 位
(integer) 9
127.0.0.1:6379> bitpos w 1 2 2 # 从第三个字符算起,第一个 1 位
(integer) 17

bitfield 命令

bitfield 用来作为批量写入或是读取。来自参考资料
bitfield 有三个子指令,分别是get/set/incrby,它们都可以对指定位片段进行读写,但是最多只能处理 64 个连续的位,如果超过 64 位,就得使用多个子指令,bitfield 可以一次执行多个子指令。

127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w get u4 0 # 从第一个位开始取 4 个位,结果是无符号数 (u)
(integer) 6
127.0.0.1:6379> bitfield w get u3 2 # 从第三个位开始取 3 个位,结果是无符号数 (u)
(integer) 5
127.0.0.1:6379> bitfield w get i4 0 # 从第一个位开始取 4 个位,结果是有符号数 (i)
1) (integer) 6
127.0.0.1:6379> bitfield w get i3 2 # 从第三个位开始取 3 个位,结果是有符号数 (i)
1) (integer) -3

所谓有符号数是指获取的位数组中第一个位是符号位,剩下的才是值。如果第一位是1,那就是负数。无符号数表示非负数,没有符号位,获取的位数组全部都是值。有符号数最多可以获取 64 位,无符号数只能获取 63 位 (因为 Redis 协议中的 integer 是有符号数,最大 64 位,不能传递 64 位无符号值)。如果超出位数限制,Redis 就会告诉你参数错误。

补充

项目中使用了 RedisTemplate ,因为像 bitcount 命令是 spring-data-redis 新版本在代码中才集成的,那么怎么办呢?可以执行脚本的方式来执行该命令。

    private static final String USER_READ_EVL = "return redis.call('bitcount',KEYS[1])";

    /**
* 获取用户已读的进度
*/
private Long getUserReadIndex(String userReadKey, Long userId) {
List<String> keys = new ArrayList<>();
keys.add(userReadKey);
List<String> args = new ArrayList<>();
RedisCallback<Long> callback = (connection) -> {
Object nativeConnection = connection.getNativeConnection();
// 集群模式
if (nativeConnection instanceof JedisCluster) {
return (Long) ((JedisCluster) nativeConnection).eval(USER_READ_EVL, keys, args);
}
// 单机模式
else if (nativeConnection instanceof Jedis) {
return (Long) ((Jedis) nativeConnection).eval(USER_READ_EVL, keys, args);
}
return 0L;
};
//key没创建的情况是 0
return mRedisTemplate.execute(callback);
}

参考资料 :

  • https://www.cnblogs.com/wuwuyong/p/11739495.html (推荐一看)
  • https://docs.spring.io/spring-data/redis/docs/current/reference/html/#redis
  • https://redis.io/commands/bitfield
  • http://redisdoc.com/bitmap/bitfield.html (中文文档,推荐一看)
上一篇:【Redis的那些事 · 上篇】Redis的介绍、五种数据结构演示和分布式锁


下一篇:php 过滤英文标点符号 过滤中文标点符号