Bitmap和布隆过滤器实现数据去重

Bitmap位图

Bitmap是bit数组,只存储0和1,适用于存储整数类型数据 

通过元素对应的位索引置1表示元素存在,后续通过位索引判断元素是否已存在

 

布隆过滤器

布隆过滤器是由一串长度固定的位数组和多组哈希函数组成。元素放入布隆过滤器中时,经过多组哈希函数运算得到多个位索引,将其置1。另外,布隆过滤器不支持删除操作

查询时判断多个索引对应的位置是否都为1,存在误判的可能。

 

数据去重

例如 对40亿个QQ号进行去重操作 

如果直接存储QQ号,则需要40*4字节=15G,会消耗大量内存,在redis存储还会造成大key问题

 

bitmap实现

初始化bitmap长度大小为2^32

在变量QQ号时,将bitmap对应位索引的位置1,如果已经为1,则记录到日志中

内存使用:2^32*1bit/8字节=512Mb

//初始化长度为2 ^ 32位的位数组
BitSet bitmap = new BitSet(1L << 32); // 需调整JVM参数 -Xmx1g
//读取QQ号,如果该位为0,标记为1;否则数据重复
while(读取QQ号) {
    if (!bitmap.get(qq)) {
        //数据不存在才set 1,存在则去重了
        bitmap.set(qq);
    }
}
//最后,遍历Bitmap位数组,标记为1的位置就是去重后的结

 

布隆过滤器实现

使用公式 m = -ln p/(ln 2)^2计算位数组大小,例如:允许1%误判率时,1亿元素需要约 958 MB 空间(比Bitmap大,但支持任意数据)

通过上述公式初始化布隆过滤器,后面操作和bitmap类似

与bitmap相比

缺点:使用的内存大于bitmap,存在误判率,不适合对误判率要求0的场景

优点:不只是对整数进行去重,还可以对url等任何数据进行去重,适用场景多

 

bitmap其他使用场景

统计在线人数

笨方法:用redis的set集合存储在线用户,以业务标识为key,用户上线时将id存入set中,获取在线人数时直接获取set的大小。会产生大key问题

使用bitmap:使用redis的bitmap实现,以业务标识为key,用户上线就将用户id(一般使用的是雪花算法生成)作为偏移量存入bitmap中,下线则将对应位置0,极大节省了内存,如果数据太大,可以考虑对位图进行分片。

 

统计签到

使用bitmap:每个用户都分配一个独立的bitmap,然后以功能上线日期为起始索引,后续位索引=当前日期-功能上线日期=天数

统计连续签到天数:先获取起始日期的索引对应的十进制数,然后一次和后面的每一位进行与运算,同时计数器进行计数,一旦与得到0则结束

// 示例:假设当天是10月5日,dayOfMonth=5
// 签到数据二进制 → 10111(表示1号到5号的签到状态:1=已签,0=未签)
Long num = result.get(0); // 十进制值为23(二进制10111)

// 核心统计逻辑
int count = 0;
while (true) {
    if ((num & 1) == 0) {  // 检查最低位(对应当月第1天)
        break;
    } else {
        count++;           // 累计连续签到天数
    }
    num = num >> 1;        // 右移1位(向高位移动)
}
// 最终count=3(错误结果,实际应统计最近连续签到)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值