布隆过滤器

2018-07-15  本文已影响0人  维特无忧堡

近期学习的时候发现了一个强大的神器,布隆过滤器,发现这个算法对大数据的去重真的很有用哎!记录一下,免得自己忘了。

概念

  首先我先来介绍一下这个算法的基本思想,假设让你实现查重的话,你肯定是用Hash表存储下来,然后判断,那么怎么存储呢?给你一个字符串,你肯定是先用hash函数映射一下,如果值的访问太大的话,可能要取个模什么的,让后这个作为标识存储在Hash表中,虽然这样做的时间复杂度不高,但空间使用率太高了,而且你想一下,你根本就不用这个串,你只是要知道是否有重复,这样布隆过滤器就诞生了。
  假设我们这边有8个不同hash函数(很完美的),4字节的一个空间(32位)(可以称之为桶),每一位都设置为0,我们分别使用这8个hash函数,然后对32取余,这样就会得到8个小于32位的数字,我们把这八个数字当作序号,把32位中对应的位设置位1,表示已经存在,这样,当我们下次再有相同的字符串的时候,我们可以看看对应位置上是不是都是1,如果是就是重复啦,如果不是就说明不在里面;
  是不是很神奇,对的。那么这个算法有没有局限呢?它是绝对不会漏掉相同的串的(因为相同的串Hash肯定是一样的),有可能会误判,这就是所谓的宁可错杀也不放过,所以说合理选择Hash函数个数很重要
  那么怎么计算这个Hash函数个数呢? 假设整个数据大小是n,容许的失误率是p
那么 hash函数的个数(我听一个大佬总结的)

m = n * ln p / (ln 2)^2

那么这个复杂度是多少呢?还是O(n)啊,判断一个串的话就是O(1),那有的人就奇怪了,判断的话不是应该是O(n)吗?不是的,一个串的唯一表示就是一个32位的空间,相当于一个int的值,就BitSet存储get的话就是O(1)

代码实现

接着来一波代码,让大家感受一下

package Filter;

import java.util.BitSet;

public class BloomFilter {
   private  static  int BIT_SIZE = 2 << 25;//可以表示的数据量 ,你可以试着调大一点
   private BitSet bitSet ;
   private int[] seeds = {3,5,7,11,13,31,37,61};
   private HashFunction[] func;
   public BloomFilter(int size) throws Exception{
       if (size <= 30 && size > 0){
           BIT_SIZE = 2 << size;
       } else {
           throw  new Exception("range illegal");
       }
       bitSet = new BitSet(BIT_SIZE);
       func = new HashFunction[seeds.length];
       for (int i = 0; i < func.length; i++){
           func[i] = new HashFunction(seeds[i],seeds.length);
       }
   }
   public void add(String val){
       if (val == null) return;
       for (HashFunction function : func){
           bitSet.set(function.hash(val),true);
       }
   }
   public boolean contain(String val){
       if (val == null) return false;
       for(HashFunction function: func){
           if(!bitSet.get(function.hash(val)))
               return false;
       }
       return true;
   }

   public static class HashFunction{
       private int seed;
       private int size;
       public HashFunction(int seed,int size){
           this.seed = seed;
           this.size = size;
       }
      //计算hash的方法,我看String源码里面写的是seed = 31,
       public int hash(String value){
           int ans = 0;
           for (char ch : value.toCharArray()){
               ans = ans * seed + ch;
           }
           return ans & (size - 1);
       }
   }
}

上一篇 下一篇

猜你喜欢

热点阅读