• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

每天一道算法练习题--Day17 和amp;和amp; 第一章 --算法专题 --- ----------布隆过滤器

武飞扬头像
Wzideng
帮助1

场景

假设你现在要处理这样一个问题,你有一个网站并且拥有很多访客,每当有用户访问时,你想知道这个 ip 是不是第一次访问你的网站。

hashtable 可以么

一个显而易见的答案是将所有的 IP 用 hashtable 存起来,每次访问都去 hashtable 中取,然后判断即可。但是题目说了网站有很多访客,假如有 10 亿个用户访问过,假设 IP 是 IPV4, 那么每个 IP 的长度是 4 byte,那么你一共需要 4 * 1000000000 = 4000000000Bytes = 4G 。

如果是判断 URL 黑名单,由于每个 URL 会更长(可能远大于上面 IPV4 地址的 4 byte),那么需要的空间可能会远远大于你的期望。

bit

另一个稍微难想到的解法是 bit, 我们知道 bit 有 0 和 1 两种状态,那么用来表示存在与不存在再合适不过了。

假如有 10 亿个 IP,就可以用 10 亿个 bit 来存储,那么你一共需要 1 * 1000000000 = (4000000000 / 8) Bytes = 128M, 变为原来的 1/32, 如果是存储 URL 这种更长的字符串,效率会更高。 问题是,我们怎么把 IPV4 和 bit 的位置关联上呢?

比如192.168.1.1 应该是用第几位表示,10.18.1.1 应该是用第几位表示呢? 答案是使用哈希函数。

基于这种想法,我们只需要两个操作,set(ip) 和 has(ip),以及一个内置函数 hash(ip) 用于将 IP 映射到 bit 表。

这样做有两个非常致命的缺点:

  • 当样本分布极度不均匀的时候,会造成很大空间上的浪费

我们可以通过优化散列函数来解决

  • 当元素不是整型(比如 URL)的时候,BitSet 就不适用了

我们还是可以使用散列函数来解决, 甚至可以多 hash 几次

布隆过滤器

布隆过滤器其实就是bit 多个散列函数。k 次 hash(ip) 会生成多个索引,并将其 k 个索引位置的二进制置为 1。

  • 如果经过 k 个索引位置的值都为 1,那么认为其可能存在(因为有冲突的可能)。
  • 如果有一个不为 1,那么一定不存在(一个值经过散列函数得到的值一定是唯一的),这也是布隆过滤器的一个重要特点。

也就是说布隆过滤器回答了:可能存在一定不存在 的问题。
学新通
从上图可以看出, 布隆过滤器本质上是由一个很长的二进制向量和多个哈希函数组成。

由于没有 hashtable 的 100% 可靠性,因此这本质上是一种可靠性换取空间的做法。除了可靠性,布隆过滤器删除起来也比较麻烦。

误报

上面提到了布隆过滤器回答了:可能存在 和 一定不存在 的问题。 因此当回答是可能存在的时候你该怎么做?一般而言, 为了宁可错杀一千,也不放过一个,我们认为他存在。 这个时候就产生了误报。

误报率和二进制向量的长度成反比。

布隆过滤器的应用

学新通

代码

public   class  MyBloomFilter {
     private static final int DEFAULT_SIZE =  2 << 31 ;
     private static final int[] seeds = new int [] {3,5,7,11,13,19,23,37 };
     private  BitSet  bits = new BitSet(DEFAULT_SIZE);
     private  SimpleHash[] func  = new  SimpleHash[seeds.length];

     public   static   void  main(String[] args) {
        //使用
        String value = "www.xxxxx.com" ;
        MyBloomFilter filter = new MyBloomFilter();
        System.out.println(filter.contains(value));
        filter.add(value);
        System.out.println(filter.contains(value));
    }
    //构造函数
     public  MyBloomFilter() {
         for  ( int  i  =   0 ; i  <  seeds.length; i    ) {
            func[i]  =   new  SimpleHash(DEFAULT_SIZE, seeds[i]);
        }
    }
     //添加网站
     public   void  add(String value) {
         for  (SimpleHash f : func) {
            bits.set(f.hash(value),  true );
        }
    }
     //判断可疑网站是否存在
     public   boolean  contains(String value) {
         if  (value  ==   null ) {
             return   false ;
        }
         boolean  ret  =   true ;
         for  (SimpleHash f : func) {
            //核心就是通过“与”的操作
            ret  =  ret  &&  bits.get(f.hash(value));
        }
         return  ret;
    }
}
学新通

总结

布隆过滤器回答了:可能存在 和 一定不存在 的问题。本质是一种空间和准确率的一个取舍。实际使用可能会有误报的情况, 如果你的业务可以接受误报,那么使用布隆过滤器进行优化是一个不错的选择。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfiiffj
系列文章
更多 icon
同类精品
更多 icon
继续加载