redis的setbit和getbit是干嘛的???

本文详细解释了 Redis 中 GETBIT 命令的工作原理及使用方法,包括如何通过计算确定二进制位的位置,并快速获取指定偏移量上的二进制位的值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://segmentfault.com/q/1010000008421660

这是我看到的对redisgetbit的讲解,感觉讲的很到位,可是就是一个也不懂:不明白这个计算公式,还有,获取偏移量上的二进制位的值有什么用呢?

GETBIT 命令用于返回位数组 bitarray 在 offset 偏移量上的二进制位的值:

GETBIT <bitarray> <offset>

GETBIT 命令的执行过程如下:

计算 byte = \lfloor offset \div 8 \rfloor , byte 值记录了 offset 偏移量指定的二进制位保存在位数组的哪个字节。
计算 bit = (offset \bmod 8) + 1 , bit 值记录了 offset 偏移量指定的二进制位是 byte 字节的第几个二进制位。
根据 byte 值和 bit 值, 在位数组 bitarray 中定位 offset 偏移量指定的二进制位, 并返回这个位的值。

举个例子, 对于图 IMAGE_BIT_EXAMPLE 所示的位数组来说, 命令:

GETBIT <bitarray> 3

将执行以下操作:

\lfloor 3 \div 8 \rfloor 的值为 0 。
(3 \bmod 8) + 1 的值为 4 。
定位到 buf[0] 字节上面, 然后取出该字节上的第 4 个二进制位(从左向右数)的值。
向客户端返回二进制位的值 1 。

命令的执行过程如图 IMAGE_SEARCH_EXAMPLE 所示。

digraph { label = "n 图 IMAGE_SEARCH_EXAMPLE 查找并返回 offset 为 3 的二进制位的过程"; // rankdir = LR; point_to_buf0 [label = "1) 定位到 buf[0] 字节", shape = plaintext]; point_to_idx3 [label = "2) 返回第 4 个二进制位的值", shape = plaintext]; buf [label = " { <buf0> buf[0] | 1 | 0 | 1 | <idx3> 1 | 0 | 0 | 1 | 0 } | { buf[1] (空字符) } ", shape = record]; // edge [style = dashed]; point_to_buf0 -> buf:buf0; point_to_idx3 -> buf:idx3; }

再举一个例子, 对于图 IMAGE_ANOTHER_BIT_EXAMPLE 所示的位数组来说, 命令:

GETBIT <bitarray> 10

将执行以下操作:

\lfloor 10 \div 8 \rfloor 的值为 1 。
(10 \bmod 8) + 1 的值为 3 。
定位到 buf[1] 字节上面, 然后取出该字节上的第 3 个二进制位的值。
向客户端返回二进制位的值 0 。

命令的执行过程如图 IMAGE_ANOTHER_SEARCH_EXAMPLE 所示。

digraph { label = "n 图 IMAGE_ANOTHER_SEARCH_EXAMPLE 查找并返回 offset 为 10 的二进制位的过程"; rankdir = LR; // node [shape = record]; buf [label = " { buf[0] | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 } | { <buf1> buf[1] | 1 | 1 | <bit> 0 | 0 | 0 | 0 | 1 | 1 } | { buf[2] | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 } | { buf[3] | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 } "]; node [shape = plaintext]; point_to_buf [label = "1) 定位到 buf[1] 字节"]; point_to_bit [label = "2) 返回第 3 个二进制位的值"]; // edge [style = dashed]; point_to_buf -> buf:buf1; point_to_bit -> buf:bit; }

因为 GETBIT 命令执行的所有操作都可以在常数时间内完成, 所以该命令的算法复杂度为 O(1) 。

我在知乎上看到的这个,相比于上面的感觉挺易懂的https://www.zhihu.com/questio...

### Redis HyperLogLog 与 Bitmap 的关系及区别 #### 1. 数据结构设计 HyperLogLog Bitmap 是 Redis 中两种不同的数据结构,各自针对特定的场景进行了优化。HyperLogLog 是一种概率性算法的数据结构,用于高效地估算集合的基数(即不重复元素的数量)。其核心思想是通过牺牲一定的精确度来大幅减少内存占用[^2]。相比之下,Bitmap 是基于位图的操作,提供了对二进制位的高效操作查询功能[^3]。 #### 2. 内存占用 HyperLogLog 的内存占用非常低,无论统计的元素数量是多少,每个 key 只需要固定大小的 12 KB 内存即可完成基数估算[^4]。而 Bitmap 的内存占用则取决于所记录的位数以及是否需要存储更多的信息。例如,如果需要记录 100 万个布尔值,则需要大约 125 KB 的内存(100 万 / 8 字节)[^3]。 #### 3. 精确性 HyperLogLog 是一种近似算法,因此在统计结果上可能存在一定的误差范围,通常为标准误差 ±0.81%[^2]。这使得它非常适合那些对精确度要求不高但对性能内存消耗敏感的应用场景。而 Bitmap 提供了完全精确的结果,因为它直接操作二进制位,没有概率性的误差。 #### 4. 操作命令 - **HyperLogLog** 的常用命令包括 `PFADD` 用于添加元素,`PFCOUNT` 用于获取当前集合的基数估计值,`PFMERGE` 用于合并多个 HyperLogLog 的数据[^4]。 - **Bitmap** 的操作主要围绕位运算展开,如 `SETBIT` 设置某个位的值,`GETBIT` 获取某个位的值,`BITCOUNT` 统计指定范围内设置为 1 的位数等[^3]。 #### 5. 应用场景 - **HyperLogLog** 更适合用于需要统计大量唯一用户或事件的应用场景,例如: - 统计某段时间内的独立访客数。 - 计算社交网络中好友关系的唯一标识。 - 在大数据分析中快速估算去重后的数据规模。 - **Bitmap** 更适用于需要频繁进行位操作或记录二元状态的场景,例如: - 用户签到系统:通过每天设置一个位来记录用户的签到情况。 - 权限管理:将权限表示为二进制位,每位代表一种权限。 - 大规模布隆过滤器实现:利用 Bitmap 的高效位操作特性[^3]。 ```python # 示例代码:使用 Bitmap 实现用户签到 import redis r = redis.Redis() # 设置第 n 天的签到状态 def set_sign_in(user_id, day): r.setbit(f"user:{user_id}:sign_in", day, 1) # 查询某天是否签到 def check_sign_in(user_id, day): return r.getbit(f"user:{user_id}:sign_in", day) # 示例代码:使用 HyperLogLog 统计独立访客 def add_unique_visitor(visitor_id): r.pfadd("unique_visitors", visitor_id) def get_unique_visitors_count(): return r.pfcount("unique_visitors") ``` ### 总结 HyperLogLog Bitmap 虽然都属于 Redis 的高级数据结构,但它们的设计目标适用场景截然不同。HyperLogLog 专注于以极低的内存开销进行基数估算,而 Bitmap 则提供了一种高效的位操作机制,适用于精确的二元状态记录查询。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值