梁山手机网站建设,设计签名的软件,wordpress 百度优化 插件,站长素材网站官网Redis基础学习#xff1a;Bitmap 与 HyperLogLog 相关操作继续进行 Redis 基础部分的学习#xff0c;今天我们学习的是两种另外的数据类型。说是数据类型#xff0c;但其实它们实际上使用的都是 String 类型做为底层基础#xff0c;只不过是在存储的时候进行了一些特殊的操…Redis基础学习Bitmap 与 HyperLogLog 相关操作继续进行 Redis 基础部分的学习今天我们学习的是两种另外的数据类型。说是数据类型但其实它们实际上使用的都是 String 类型做为底层基础只不过是在存储的时候进行了一些特殊的操作。换句话说这两种类型并不是真正意义上的“数据类型”换成“数据操作”可能更合适一些。Bitmap先来看看 Bitmap 这是个啥玩意其实呀这个就是 位图 Bit 就是 比特 的意思嘛。一提到 比特 是不是又得来二进制了这个真没办法学计算机的任何工具都逃不掉的就是 二进制 相关的操作。不过在 Redis 中的操作还是比较简单的毕竟我们主要的操作还是在程序业务端进行Redis 只是一个数据库而已。Bitmap 在 Redis 中可以存储大约 40 多亿条数据或者说是40多亿个 0 和 1 位。估计不少小伙伴马上就能想到它的应用场景了我们在最后再说。先来看看它的操作。Bitmap 操作命令设置和获取指定位置的位信息直接使用 SETBIT 和 GETBIT。127.0.0.1:6379 setbit a 8 1
(integer) 0
127.0.0.1:6379 setbit a 4 1
(integer) 0
127.0.0.1:6379 get a
\b\x80
127.0.0.1:6379 getbit a 4
(integer) 1
127.0.0.1:6379 getbit a 5
(integer) 0注意到上面的例子我们直接使用 GET 命令也可以获取到内容前面就说过了它本身就是使用 String 类型存储的。只不过使用位操作的话我们要理解 8 位代表 1 个字节的问题。因此设置一个 8 位的二进制代码才能表示出一个我们能看懂的字符。127.0.0.1:6379 setbit b 1 1
(integer) 0
127.0.0.1:6379 setbit b 4 1
(integer) 0
127.0.0.1:6379 setbit b 5 1
(integer) 0
127.0.0.1:6379 setbit b 6 1
(integer) 0
127.0.0.1:6379 setbit b 7 1
(integer) 0
127.0.0.1:6379 get b
O
127.0.0.1:6379 setbit c 1 1
(integer) 0
127.0.0.1:6379 setbit c 2 1
(integer) 0
127.0.0.1:6379 setbit c 4 1
(integer) 0
127.0.0.1:6379 setbit c 6 1
(integer) 0
127.0.0.1:6379 setbit c 7 1
(integer) 0
127.0.0.1:6379 get c
k看出上面的例子是什么意思了吗第一个 b 设置的其实是 01001111 转换成十进制是 79 对应的 ASC2 码就是大写英文 O 。另一个 c 也是一样的意思01101011 的十进制是 107 表示的英文是 107 。如果要表示 Ok 这两个字母的话就需要两个 8 位也就是两个字节 01001111 01101011 。127.0.0.1:6379 setbit d 1 1
(integer) 0
127.0.0.1:6379 setbit d 4 1
(integer) 0
127.0.0.1:6379 setbit d 5 1
(integer) 0
127.0.0.1:6379 setbit d 6 1
(integer) 0
127.0.0.1:6379 setbit d 7 1
(integer) 0
127.0.0.1:6379 get d
O
127.0.0.1:6379 setbit d 9 1
(integer) 0
127.0.0.1:6379 setbit d 10 1
(integer) 0
127.0.0.1:6379 setbit d 12 1
(integer) 0
127.0.0.1:6379 setbit d 14 1
(integer) 0
127.0.0.1:6379 setbit d 15 1
(integer) 0
127.0.0.1:6379 get d
Ok好玩吧中文也是一样的只是三个字节的 UTF8 编码需要三个 8 位的数据才能表示一个中文字大家可以试试哦。127.0.0.1:6379 set s 中
OK
127.0.0.1:6379 get s
\xe4\xb8\xad
127.0.0.1:6379 getbit s 0
(integer) 1
127.0.0.1:6379 getbit s 1
(integer) 1
127.0.0.1:6379 getbit s 2
(integer) 1
127.0.0.1:6379 getbit s 3
(integer) 0“中”这个字直接 GET 返回的是16进制数据将 e4b8ad 转换成二进制是 11100100 10111000 10101101 然后我们就可以使用 GETBIT 来验证是不是和我们手动转换出来的是一样的结果。大家有兴趣的可以再多了解一下字符编码相关的知识比如在 Redis 中使用的 UTF8 为什么单个字节第一位只能是 0 必须是 0xxxxxxx 这样的中文也都是固定的 1110xxxx 10xxxxxx 10xxxxxx 这种格式很有意思哦。位操作既然是位操作那么 与、或、异或、非 操作肯定要有啦。127.0.0.1:6379 bitop or dd b c
(integer) 1
127.0.0.1:6379 get dd
o
127.0.0.1:6379 bitop and dd b c
(integer) 1
127.0.0.1:6379 get dd
K
127.0.0.1:6379 bitop xor dd b c
(integer) 1
127.0.0.1:6379 get dd
$
127.0.0.1:6379 bitop not dd b
(integer) 1
127.0.0.1:6379 get dd
\xb0查询第一个bit位位置通过 BITPOS 命令可以查询到指定的 key 中第一个出现的位数据的位置。127.0.0.1:6379 BITPOS a 1
(integer) 4
127.0.0.1:6379 BITPOS a 0
(integer) 0第一条命令是查询第一个 1 出现的位置第二条命令是查询第一个 0 出现的位置。它还有第二个参数这个参数是一个偏移量不过需要注意的是它指的是字节的偏移量不是位的偏移量。127.0.0.1:6379 BITPOS d 1 0
(integer) 1
127.0.0.1:6379 BITPOS d 1 1
(integer) 9
127.0.0.1:6379 BITPOS d 1 2
(integer) -1统计数量BITCOUNT 可以统计指定 key 中 1 出现的次数。127.0.0.1:6379 BITCOUNT d
(integer) 10
127.0.0.1:6379 BITCOUNT d 1 0 2
(error) ERR syntax error
127.0.0.1:6379 BITCOUNT d 1 0 1
(error) ERR syntax error
127.0.0.1:6379 BITCOUNT d 1 2
(integer) 5
127.0.0.1:6379 BITCOUNT d 0 2
(integer) 10
127.0.0.1:6379 BITCOUNT d 2 3
(integer) 0它还有两个参数同样也是字节偏移量和长度。位域操作位域这个东西我就不太懂了只是给个例子这一块深入学过 C 的同学应该会比较了解。127.0.0.1:6379 setbit e 1 1
(integer) 0
127.0.0.1:6379 get e127.0.0.1:6379 BITFIELD e incrby i5 100 1 get u4 0
1) (integer) 1
2) (integer) 4
127.0.0.1:6379 get e
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80Bitmap 经典例子好了Bitmap 的基本操作就是上面那些介绍的比较简单不过也确实都不复杂。但前提是要对二进制和进制之间的转换以及字符编码要有一定的了解。如果我们只是为了去显示字符串的位那就有点大材小用了其实 Bitmap 有个非常强悍的能力也就是运用 BITCOUNT 去进行数据统计。包括官网上给出的也是类似这样的例子统计登录用户数。最开始我们已经知道一个 key 可以保存40多亿个位那么我们可以把用户id当作位索引然后某个用户今天登录了就给它的位设置为 1 然后就可以 BITCOUNT 快速统计出今天有多少用户登录了系统速度相当快哦。127.0.0.1:6379 setbit user_login_20220509 100010 1
(integer) 0
127.0.0.1:6379 setbit user_login_20220509 25525 1
(integer) 0
127.0.0.1:6379 setbit user_login_20220509 8782 1
(integer) 0
127.0.0.1:6379 setbit user_login_20220509 9846526547 1
(error) ERR bit offset is not an integer or out of range
127.0.0.1:6379 setbit user_login_20220509 98465265 1
(integer) 0
127.0.0.1:6379 setbit user_login_20220509 399999999 1
(integer) 0
127.0.0.1:6379 setbit user_login_20220509 3999999999 1
(integer) 0
127.0.0.1:6379 setbit user_login_20220509 4294967295 1
(integer) 0
127.0.0.1:6379 setbit user_login_20220509 4294967296 1
(error) ERR bit offset is not an integer or out of range
127.0.0.1:6379 BITCOUNT user_login_20220509
(integer) 7HyperLogLog既然说到统计了那么 HyperLogLog 这个操作类型就不得不提了。它是一种概率数据结构用于计算唯一事物的集合数量。同时它是以内存换精度的也就是说它能极大的节约内存但是会有精度丢失的问题。最坏情况下也就是内存占用最大的情况下它也只需要 12K 的内存容量就可以存储非常巨大的数据量精度的丢失会在 1% 以内。它也可以实现上面 Bitmap 中统计的例子我们先来看看相关的操作命令。127.0.0.1:6379 pfadd hll a b c d e f g
(integer) 1
127.0.0.1:6379 pfcount hll
(integer) 7
127.0.0.1:6379 pfadd hll a b c d e f g h i j k
(integer) 1
127.0.0.1:6379 pfcount hll
(integer) 11PFADD 添加数据PFCOUNT 获取数量。基本的操作命令就这两个是不是无敌了。除了这两个外还有一个合并的命令类似于集合的并集操作。127.0.0.1:6379 PFADD pfa a b c d e f
(integer) 1
127.0.0.1:6379 PFADD pfb d c a e g i
(integer) 1
127.0.0.1:6379 pfadd pfc b d f i l m n o
(integer) 1
127.0.0.1:6379 PFMERGE pfmerge pfa pfb pfc
OK
127.0.0.1:6379 pfcount pfmerge
(integer) 12另外它也是以 String 为基本存储类型的所以用 GET 也能看到内容。127.0.0.1:6379 get hll
HYLL\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00Fm\x80I\xe8\x80L\\x80D\x848\x80B\x80K\x83\x80B\xed\x84A\xfc\x8cG\x8e\x80Bm\x80BZ好了接下来说下 HyperLogLog 和其它方式统计的对比以下是网上找到的相关文章获取到的资料。如果我们使用 SET 来进行基数统计那么假设每一个元素的 32Bit(2^24 ≈ 1600万; 2^32 ≈ 42亿) 假设存储1亿个不重复的元素那么我们需要 100 000 000 * 32 /8/1024/1024 ≈ 381MB。如果我们用 Bitmap 来进行基数统计每个元素对应一位(bit)假设我们存储1亿个不重复的元素那么我们需要 100 000 000 /8/1024/1024 ≈ 12MB。然而我们使用 HyperLogLog 一个键占用的内容空间是12KB并且这个键可以处理海量数据。它们三个都可以应用在统计不重复元素的场景HyperLogLog海量数据可以忍受 0.81% 误差的场景其实大数据处理的时候都会有误差。Bitmap数据量不大不能忍受误差元素连续的自增的用户主键id。SET数据量不大不能忍受误差元素没有规律并且需要返回实际的单个元素。总结今天的内容挺好玩吧Bitmap 和 HyperLogLog 最常用的其实都是一个不重复数据统计的场景但是又各有优势。在日常的工作中如果有类似的应用场景完全就可以使用这两种数据操作来试试了。扩展知识布隆过滤器布隆过滤器Bloom Filter听说过没面试有没有被坑过跟你说布隆过滤器的基础知识就是 Bitmap HyperLogLog 也是它的类似实现之一。啥叫布隆过滤器就是能够快速地查找某一个元素是否存在于指定的集合中最典型的做法就是使用二进制位来进行操作这不就是 Bitmap 嘛。当然完整的布隆过滤器的实现还是要更复杂一些它一般会有三个 Hash 函数生成三个不同位置只有当三个位置全部命中时才会认为指定的数据已经存在。从这一点上来说其实就是在有限的空间内可以存放更多的数据。但它也会出现不同的数据三个 Hash 函数计算结果一致的概率但我们可以增加更多的 Hash 函数不过相应地性能也会降低。同样它也会有精度问题反正大概原理就是这样。布隆过滤器有一个非常经典的名言那就是“我说你不在那你一定不在我说你存在你有可能存在也可能不存在”。在 packgist 上也能搜到纯 PHP 实现布隆过滤器的 Composer 包大家可以自己下载源码学习一下哦