• 关于布隆过滤器


    布隆过滤器,名字听起来有点奇怪,其实是根据一个人的名字来命名的。

    布隆过滤器在wiki上的介绍:

    布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难

    布隆过滤器使用场景:

    1.网页黑名单系统、

    2.垃圾邮件过滤系统、

    3.爬虫的网址判重系统

    4.解决缓存穿透问题

    为啥要用这鬼东西?

       数据量很大,数十亿甚至更多,内存装不下且数据库检索又极慢的情况,我们不妨考虑下布隆过滤器,因为它是一个空间效率占用极少和查询时间极快的算法。

    布隆过滤器的自我介绍:

    布隆过滤器。有一个长度为m的bit型数组,如我们所知,每个位置只占一个bit,每个位置只有0和1两种状态。假设一共有k个哈希函数相互独立,输入域都为s且都大于等于m,那么对同一个输入对象(可以想象为缓存中的一个key),经过k个哈希函数计算出来的结果也都是独立的。对算出来的每一个结果都对m取余,然后在bit数组上把相应的位置设置为1(描黑),如下图所示:

     简而言之:输入对象-->哈希函数计算-->计算结果对M取余。

    至此一个输入对象对bit array集合的影响过程就结束了,我们可以看到会有多个位置被描黑,也就是设置为1.

    接下来所有的输入对象都按照这种方式去描黑数组,最终一个布隆过滤器就生成了,它代表了所有输入对象组成的集合。
    那么如何判断一个对象是否在过滤器中呢?假设一个输入对象为hash1,我们需要通过看k个哈希函数算出k个值,然后把k个值取余(%m),就得到了k个[0,m-1]的值。然后我们判断bit array上这k个值是否都为黑,如果有一个不为黑,那么肯定hash1肯定不在这个集合里。如果都为黑,则说明hash1在集合里,但有可能误判。因为当输入对象过多,而集合过小,会导致集合中大多位置都会被描黑,那么在检查hash1时,有可能hash1对应的k个位置正好被描黑了,然后错误的认为hash1存在集合里。

    控制布隆过滤器的误判率

    如果bit array集合的大小m相比于输入对象的个数过小,失误率就会变高。这里直接引入一个已经得到证明的公式,根据输入对象数量n和我们想要达到的误判率为p计算出布隆过滤器的大小m和哈希函数的个数k.
    布隆过滤器的大小m公式:

    哈希函数的个数k公式:

    布隆过滤器真实失误率p公式:

    假设我们的缓存系统,key为userId,value为user。如果我们有10亿个用户,规定失误率不能超过0.01%,通过计算器计算可得m=19.17n,向上取整为20n,也就是需要200亿个bit,换算之后所需内存大小就是2.3G。通过第二个公式可计算出所需哈希函数k=14.因为在计算m的时候用了向上取整,所以真是的误判率绝对小于等于0.01%。

    (科普下:1KB=1024bit,1M=1024KB,1G=1024M)

    那么项目中如何使用布隆过滤器呢?

    其实人家外国人已经实现过了,唉,难道我大中华就没有自己开发的吗,老是用人家的轮子。

    不过用一下就用一下吧。

    步骤:

    1.引入pom依赖:

    <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>25.1-jre</version>
    </dependency>

    2.使用的代码例子:

    public static void main(String... args){
            /**
             * 创建一个插入对象为十亿,误报率为0.01%的布隆过滤器
             */
            BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")), 1000000000, 0.0001);
            bloomFilter.put("121");
            bloomFilter.put("122");
            bloomFilter.put("123");
            System.out.println(bloomFilter.mightContain("121"));
        }

    说到这个可能包含,mightContain,我想要是查询下全中国人有多少人没发年终奖,没发的发一个月工资,刚好我这个没发年终奖的人显示已经发了,那我就惨了。

    ----------天道酬勤----------------
  • 相关阅读:
    流程控制之while循环
    流程控制之if判断
    基本运算符
    格式化输出的三种方式
    Python与用户交互
    解压缩
    布尔类型
    字典类型
    列表类型
    字符串类型
  • 原文地址:https://www.cnblogs.com/jiliunyongjin/p/14362517.html
Copyright © 2020-2023  润新知