布隆过滤器(BloomFilter)——原理(二)

布隆过滤器(BloomFilter)——原理(二)

1. HashSet、HashMap数据结构简介

  • 为了方便对比,所以我们先来看一下实现同类功能、常用的集合框架。因为HashSet一般由value为同一个Object的HashMap封装而成,所以咱们直接看看HashMap即可。
  • 结构图如下:
    HashMap结构图
  • 结构说明
    1. 首先构建一个长度为n的数组
    2. 当向其中存入数据的时候,先计算对象的HashCode,用HashCode % n的结果决定存入数组的角标位置
    3. 但由于不同对象计算出的HashCode % n 的值可能相同,所以数组的同一个角标的位置需要存储多个元素
    4. 这时就采用链表或者红黑树来存在多个对象,并且此时采用equals来确定两个对象是否是同一个

2. BloomFilter的结构

  • 首先够一个长度为n的bit数组,例如 n = 2 31 2^{31} -1(非负int的最大值),将数组所有位置的值设定为0
    bloomfilter_1
  • 计算每个待存入的对象的信息指纹(例如由8位int组成的信息指纹: 352, 1001, 5087, 28721, 72737, 201098, 9749111, 25010128,你也可以计算5个数字的信息指纹,数字都可以,这涉及到误判率的问题),前面HashMap中求的是HashCode
    bloomfilter_2
  • 当存入一个元素时,根据其8个信息指纹,将数组对应角标的位置的值设置为1
    bloomfilter_3
  • 依次计算所有待插入的对象的信息指纹,并将该bit数组这些角标位置的值设置为1(重复的角标不管,还是设置为1),即可。这样就构成了一个BloomFilter。

3. 关于BloomFliter一些疑惑的解释

  • BloomFliter如何查询元素呢?怎么看一个对象是否存在于BloomFliter中呢?
    1. 首先计算对象的信息指纹,8个int,例如: 10, 46, 12, 234, 4564, 122, 1211234, 227341
    2. 接着,查询BloomFliter,看这8个Int对应的角标的是否都为1,只要有一个值不为1,那么立即停止查询,返回false,如果全为1,那么返回true
  • 为什么BloomFliter会有误判率?
    • 细看上面查询的解释,大家应该发现了,2个对象算出来的信息指纹数字可能部分相同,如果对象越来越多,那么就可能出现"一个对象根本根本不存在BloomFliter中,却会被判定为存在,返回true"。这就是BloomFliter的误判率出现的原因,设定一个一定容量的数组,如果元素越加越多,误判率就会越来越高!
  • 为什么BloomFliter不能删除元素呢?
    • 还是先思考前面的解释,2个对象算出来的信息指纹数字可能部分相同,当一个对象的信息指纹对应的角标的值被清除(即设定为0),那么很可能就会影响到bits数组中其他对象的信息指纹!!所以不可以这样做!
    • 你可能会说,我可以设置一个int数组,每次添加对象,对计算出对象指纹的索引位置加1,这样每次删除对象时,我可以直接对指纹的索引位置减1,判断对象是否存在的时候,可以看指纹索引对应的位置是否大于0。但是,如果一个对象被删除时,8个数字对应的索引位的值都没被减为0,那这个对象还是会被判做存在。同时,int相比bit占据的数据量大太多了(java中一个int占4字节,每个字节占8bit位)。即便使用byte(1个字节,8bit位)表示一个数字,也是bit的8倍,同时一个byte能表示数字上限是127,但实际情况下,数据量太大,很可能数组中有的索引位置被“加1”的次数超过127。
发布了128 篇原创文章 · 获赞 45 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/alionsss/article/details/99769147