zoukankan      html  css  js  c++  java
  • Bloom Filter算法

    转自网络

    集合数据结构一般都有这么一个方法:contains。其作用就是判断给定的元素是否存在集合中,这是一个常用的方法。其最简单的内部实现即遍历集合内的元素,一个个的判断是否与给定元素相等。为了更高效点我们甚至可以采用“更好的(好是相对的)”算法实现。比如如果该集合是已经排序的,那么我们用二分查找来实现contains肯定更好。但是,如果集合的数据量庞大到一定程度,大部分我们熟知的算法不再有什么用了。即使可以使用,但是机器内存也不允许。

    而Bloom Filter就是这么一个空间利用率非常高的算法。我们先来看看这个算法的原理:

    1 首先我们有一个长度为n的比特数组,开始的时候将这个比特数组里所有的元素都初始化为0

    00000000000000000000

    上面的比特数组n为20

    2 然后选取k个哈希函数,这k个哈希函数产生的结果的值的范围在0到n-1之间(对于上面的比特数组,即0到19) 。对每个要添加进集合的对象进行哈希运算,然后将哈希计算结果作为数组的索引,将索引位置的比特位设置为1(不管该比特位原先为0还是为1)。

    比如我们选取三个哈希函数,对于对象A哈希值为0,5,7。那么比特数组就为:

    10000101000000000000

    对象B的值为2,8,13,那么添加B后的比特数组为:

    10100101100001000000

    对象C为0,4,7(对象C的第一个哈希函数的值与对象A的相同了,没关系我们还是设置为1就可以了):

    10101101100001000000

    现在我们的Bloom Filter里已经有3个元素了。现在我们要判断某元素X是否在该集合中。就相当于我们要实现一个contains方法。那么这个方法如何实现呢?

    对元素X采用相同的三个哈希函数哈希,然后以这三个哈希值为索引去比特数组里找。如果三个索引位置的比特位都为1我们就认为该元素在集合中,否则不是。

    我们可以用伪代码简单的描述一下这个算法:

    public class BloomFilter{
        private bit[] bitSet = new bit[N];
    
        public void add(Object element){
          int[] hashValues = getHashValues(element);
          for(int i : hashValues){
             bitSet[i] = 1;
          }
        }
    
        public boolean contains(Object element){
            int[] hashValues = getHashValues(element);
            for(int i : hashValues){
               if(bitSet[i] != 1) return false;
            }
            return true;
        }

    算法还是挺直观的,对不。想想,一个很大的对象,经过一哈希,然后就变成了Bloom Filter里面的一个比特,这个空间利用效率是多么高啊。如果哈希函数的实现效率也很高的话那么不仅空间利用率高,时间复杂度也低啊。这真是一个神奇的算法对吧。

    可能你想,以后我就把我们那个啥数组的contains方法替换成Bloom Filter的实现吧。

    不过你仔细验证过这个算法没,它存在一些问题。这个算法有以下这么几个特征:

    1 如果该元素真的在集合中,那么Bloom Filter的contains方法肯定会返回true,这就是Bloom Filter不会漏报的特性。

    2 如果该元素不在集合中,但Bloom Filter的contains方法有可能返回true。因为不同的元素经过哈希之后哈希值可能发生碰撞。这是Bloom Filter有可能误报的特性。但是这个误报的几率并不高。

    根据这两个特性Bloom Filter在大量数据时还是挺有用的。比如假设我们有一个缓存服务器集群,集群里的不同的服务器承担的缓存也不尽相同。如果一个用户请求过来了,我们如何能快速的判断出用户请求的这个url在集群里哪台服务器上呢?因为每台服务器上缓存的url对应的页面非常庞大,我们全部弄到内存里代价也很高。我们就可以在每台服务器上放一个Bloom Filter,里面添加的都是本服务器上有缓存的那些url。这样即使Bloom Filter误报了,那就是把一个url发到了一个并不持有该url对应的缓存的服务器上,结果就是缓存未命中,缓存服务器只需要将该url打到后端的上游服务器就好了。

    根据Bloom Filter的特征我们可以看到不是所有的场景都可以用的,只有在一些能容许少量的误报的情况下使用才行。该算法用很低的误报率却换来了大量的存储空间,实在是是一个很巧妙的算法。 

     Bloom Filter算法:http://en.wikipedia.org/wiki/Bloom_filter

  • 相关阅读:
    数据可视化之DAX篇(二十五)PowerBI常用的度量值:累计至今
    数据可视化之DAX篇(二十四)Power BI应用技巧:在总计行实现条件格式
    Type-generic math (Numerics) – C 中文开发手册
    Bootstrap4 卡片
    Linux let 命令
    PHP ftp_fput() 函数
    如何从SQL Server DateTime数据类型返回日期
    ID选择器 | ID selectors (Selectors) – CSS 中文开发手册
    git write-tree (Plumbing Commands) – Git 中文开发手册
    C 库函数 – strtod()
  • 原文地址:https://www.cnblogs.com/sky0917/p/3862579.html
Copyright © 2011-2022 走看看