位图与布隆过滤器

位图与布隆过滤器

位运算

了解位图, 首先得了解二进制位运算
大家可以通过下面的链接, 了解一下;

JS中的按位操作符

你说你会位运算,那你用位运算来解下八皇后问题吧

位图

什么是位图

推荐阅读 小灰算法-位图

位图: 在我看来就是通过使用一个字符或者数字, 来代表多个 1或0 的状态;
从而节省空间;

举个例子:
用户1和用户3都是程序员. 用户2,4不是

就可以使用二进制 (1表示是, 0表示不是) 0101 来表示这个情况

大家可以参考代码:

public class BitMap { // Java中char类型占16bit,也即是2个字节
  private char[] bytes;
  private int nbits;
  
  public BitMap(int nbits) {
    this.nbits = nbits;
    this.bytes = new char[nbits/16+1];
  }

  public void set(int k) {
    if (k > nbits) return;
    int byteIndex = k / 16;
    int bitIndex = k % 16;
    // 1 << bitIndex 把 1 向左移动 bitIndex
    // |=  表示 或等于  
    // 这句话可以让 该位置的bit 设置为 1
    bytes[byteIndex] |= (1 << bitIndex);
  }

  public boolean get(int k) {
    if (k > nbits) return false;
    int byteIndex = k / 16;
    int bitIndex = k % 16;
    return (bytes[byteIndex] & (1 << bitIndex)) != 0;
  }
}

为什么要使用位图

答: 因为节省空间

在计算机中, 数据都是以二进制的方式存储的;

在编程语言中 (例如Java) 变量所占的空间是相对固定的;
例如, bool 就是占1个字节, long 占8个字节;

假设现在有一个需求: 我们需要对用户加上标签 geek;
我们有1000w用户;

方案1: 我们把用户的id, 放到一个hashmap中, 以用户的id为key,
如果用户是 geek 那么我们就把这个id的值设置为 true

这个方法是最容易想到的, 也是最好理解的;
但是, 不好的就是比较占空间;

一个int占4个字节, 1000w用户就是40M;

这么一看40M, 占用的空间不大;
但是, 这只是一个标签, 如果我们有几十个, 上百个, 内存肯定就不够用;

方案2: 我们使用1000w个bit, 来表示这1000w用户是否是geek;

例如 id为 100000001 的用户是geek, 那么第100000001位 的数据就是1;
这样空间上, 1000w用户会占用大概 12M左右的空间;

位图的好处与缺点

好处:

  • 在上一节已经说明了, 就是节省空间;
  • 可以借助位运算, 能够很快的对比出有多个标签的同一个人, 或者有标签1或标签2的人

这一点, 简单说一下;
假如有标签 geek 的用户bitmap是 1001 0110
有标签 cool 的用户的 bitmap 是 0101 0100

如果我需要找到一个用户他同时是 geek 和 cool
那么, 我只需要把两个二进制数 进行 与运算 就可以得到;

如果, 需要找到用户是geek 或者 cool, 那么需要做 或运算 即可;

但是, 如果是 找到不是 geek的用户, 就不能使用 非运算了!
因为: 如果直接取反, 数据有可能是对不上的;
我们的用户是1000w, 可能中间有的数据被删除了, id是不连贯的;
所以, 不能够直接使用取反的数据;

坏处:

坏处

  • 会浪费空间;

是不是感觉很不太对, 明明很节省空间的, 怎么又会浪费空间了呢?
因为: 在数据的范围特别大, 但是数据量很小. 那么这个bitmap 就会非常的稀疏;

例如: 我们统计出现过的数字
数据量是100 , 数据范围是 整数 从1到10亿的数据

如果使用bitmap, 就需要10亿个字节存储;
如果使用hashmap 就只需要 800个字节;

我们可以使用 布隆过滤器 来优化位图;

位图适用于哪种业务场景

位图适用的场景有

  • 用户标签
  • URL查重
  • 数据排序
  • 等等

它们都有一个特点, 就是数据的范围比较大, 数据量也比较大;
同时, 它们只需要一个 1/0 的状态即可;

参考-大数据常用技巧之位图法

redis

redis 中提供了很方便的位图运算
使用起来很方便; 真香警告!

redis 是使用 string 来存储位图

# 设置 第 111 位 为 1
setbit bit_map 111 1 

getbit bit_map 111

# 会得到一个字符串
get bit_map 

使用Bitmap来存储海量用户标签系统

布隆过滤器

刚刚说过, 当数据范围很大时, 位图所占的bit位也会很大;

例如: 如果存储数据范围 从0 到 10亿的数据;
那么, 会需要10亿个bit位;

那么, 有没有什么办法能让位图所占的空间变小, 同时却能存储更多的信息呢?

什么是布隆过滤器

布隆过滤器 (Bloom Filter) 是基于位图的,是对位图的一种改进。

还是举例 10亿个数据;

布隆过滤器的做法是,我们使用一个 1 亿个二进制大小的位图,
然后通过哈希函数,对数字进行处理,让它落在这 1 到 1 亿范围内.

举例说明:

在这里插入图片描述

一个数字通过 多个hash 函数确定多个bit的位置;
只有这几个位置都是 1 , 才认定 这个点为 1; 否则就是 0;

但是, 布隆过滤器的误判有一个特点,那就是,它只会对存在的情况有误判

如果某个数字经过布隆过滤器判断不存在,那说明这个数字真的不存在,不会发生误判;

如果某个数字经过布隆过滤器判断存在,这个时候才会有可能误判,有可能并不存在。
不过,只要我们调整哈希函数的个数、位图大小跟要存储数字的个数之间的比例,那就可以将这种误判的概率降到非常低。

布隆过滤器解决了位图的什么问题

解决了位图在数据范围较大时, 所占空间较大的问题

布隆过滤器的好处与缺点

好处

  • 节省空间

缺点

  • 判断为1时, 存在误判的情况;

布隆过滤器适用于哪种业务场景

布隆过滤器非常适合这种不需要 100% 准确的、
允许存在小概率误判的大规模判重场景。除了爬虫网页去重这个例子,
还有比如统计一个大型网站的每天的 UV 数,也就是每天有多少用户访问了网站,我们就可以使用布隆过滤器,对重复访问的用户进行去重。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值