不积跬步,无以至千里;不积小流,无以成江海。
之前写过一篇关于 BitMap 的文章,写的并不通透,在大数据下 BitMap 优势还是显而易见的,所以决定重写,面试的时候你能掌握以下绝对是你的加分项。
在我们平时开发过程中,难免会有一些 <strong>bool 型 数据需要存取
比如以下场景:
- 某个用户是否点赞过某篇文章
- 某个用户今天是否登陆过
- 某个用户的签到情况
- 统计产品的月活
什么是 BitMap
位图 并不是特殊的数据结构,它的内容其实就是普通的字符串,也就是 <strong>byte数组,用二进制表示,只有 0 和 1
我们可以使用普通的 <strong>get/set 直接获取和设置 整个位图 的内容也可以使用位图操作 <strong>getbit/setbit 等将 <strong>byte 数组 看成<strong>「位数组」来处理。
如下:
用法
居然不支持 MarkDown, 只有截图上来了。
优势
- 基于最小的单位 bit 进行存储,节省空间。
- set 时间复杂度 O(1)、get 时间复杂度 O(n),操作是非常快的。
- 二进制数据的存储,进行相关计算的时候非常快。
- 自动扩容,如果设置了某个偏移位置超出了现有的内容范围,就会 自动 将位数组进行零扩充。
弊端
- redis中bit映射被限制在512MB之内,所以最大是2^32位,再大时需要分片存取。建议每个key的位数都进行控制,因为读取时候时间复杂度O(n),越大的串读的时间花销越多。
- offset 稀疏时不建议用,浪费大量内存
空间、时间粗略计算方式
在一台 2010MacBook Pro上,offset 为 2^32-1(分配512MB)需要~300ms,
offset为2^30-1(分配128MB)需要~80ms,
offset为2^28-1(分配32MB)需要~30ms,
offset为2^26-1(分配8MB)需要8ms。
大概的空间占用计算公式是:($offset/8/1024/1024)MB
使用场景
用户签到
记录用户每天签到情况,同时能快速知道用户某天是否签到
伪代码:
活跃用户
统计某段时间内的活跃用户 只需要一个key,然后用户id为偏移量offset,如果登陆过就设置为1,反之就设置为0,
伪代码:
视频属性的无限延伸
一个拥有亿级数据量的短视频app,视频存在各种属性(是否加锁、是否特效等等),需要做各种标记。数据量大又无限延伸, BitMap可能会达到瓶颈,我们考虑用分片来处理。
key:由属性id+视频分片id组成。value:按照视频id对分片 来决定偏移量offset
以上只是举了几个典型的例子,具体情况具体分析该如何设计key 和 offset。
避坑
bitcout bitpos 的 start end 都是 <strong>字节索引
有图有真相:
点关注 不迷路
以上就是这篇的全部内容,能看到这里的都是 <strong>人才。
如果你从本篇内容有收获,求 <strong>点赞,求 <strong>关注
,求 <strong>转发 ,让更多的人学习到。如果本文有任何错误,请批评指教,不胜感激 !
閱讀更多 不住隔壁的王老師 的文章