布隆过滤器面试如何快速判断元素是否在集合里

 更新时间:2022年03月10日 08:49:07   作者:Q.E.D  
这篇文章主要为大家介绍了布隆过滤器面试中如何快速判断元素是否在集合里的完美回复,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步

如何快速判断一个元素是不是在一个集合里?这个题目是我最近面试的时候常问的一个问题,这个问题不同人都有很多不同的回答。

今天想介绍一个很少有人会提及到的方案,那就是借助布隆过滤器。

1、什么叫布隆过滤器

布隆过滤器(Bloom Filter)是一个叫做 Bloom 的老哥于1970年提出的。

实际上可以把它看作由二进制向量(或者说位数组)和一系列随机映射函数(哈希函数)两部分组成的数据结构。

它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。

图片

2、实现原理

先来一张图

图片

 布隆过滤器算法主要思想就是利用 n 个哈希函数进行 hash 过后,得到不同的哈希值,根据 hash 映射到数组(这个数组的长度可能会很长很长)的不同的索引位置上,然后将相应的索引位上的值设置为1。

判断该元素是否出现在集合中,就是利用k个不同的哈希函数计算哈希值,看哈希值对应相应索引位置上面的值是否是1,如果有1个不是1,说明该元素不存在在集合中。

但是也有可能判断元素在集合中,但是元素不在,这个元素所有索引位置上面的1都是别的元素设置的,这就导致一定的误判几率(这就是为什么上面是活可能在一个集合中的根本原因,因为会存在一定的 hash 冲突)。

注意:误判率越低,相应的性能就会越低。

3、作用

布隆过滤器是可以用于判断一个元素是不是(可能)在一个集合里,并且相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。

注意上面的一个词:可能。这里先预留一个悬念,下文会详细分析到。

判断给定数据是否存在

防止缓存穿透(判断请求的数据是否有效避免直接绕过缓存请求数据库)等等、邮箱的垃圾邮件过滤、黑名单功能等等。

4、具体实现

看完了布隆过滤器的算法思想,那就开始具体的实现的讲解。

我先来举个例子,假设有旺财和小强两个字符串,他们分别经过三次的 hash 算法,然后根据 hash 的结果将对应的数组(假设数组长度为 16)的索引位置的值置为1,先来看下旺财这个词组:

图片

旺财经过三次 hash 过后,值分别为2,4,6 那么根据可以得到索引值分别为 2、4、6,于是就将该数组的索引(2、4、6)位置的值置为1,其余当做是0,现在假设需要查找旺财 ,同样经过这个三个hash 然后发现得到的索引 2、4、6对应的位置的值都为1,那么可以判断旺财可能是存在的。

接着有将小强插入到布隆过滤器中,实际的过程和上面的一样,假设得到的下标是 1、3、5

图片

抛开旺财的存在,小强此时是这样子在布隆过滤器中的,结合旺财和小强实际的数组是这样子的:

图片

 现在有来一个数据:9527,现在要求是判断 9527 是否存在,假设9527 经过三次 hash 过后得到的下标分别为:5、6、7。结果发现下标为 7 的位置的值为0,那么可以肯定的判断出,9527 一定不存在。

接着又来了一个 国产007,经过三次 hash 过后得到的下标分别为:2、3、5,结果发现 2、3、5下标对应的值全是1,于是可以大致判断出 国产007可能存在。但是实际上经过我们刚刚的演示,国产007 根本就不存在,之所以 2、3、5 索引位置的值为1 ,那是因为其他的数据设置的。

说到这里,不知道大家有没有明白布隆过滤器的作用。

5、代码的实现

作为 java 程序员,我们真的是很幸福了,我们使用到很多的框架和工具,基本都被封装好了,布隆过滤器,我们就使用 google 封装好的工具类。当然还有其他方法,大家可以探索探索。

首先添加依赖

<!--布隆过滤依赖-->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>25.1-jre</version>
</dependency>

代码的实现

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import java.nio.charset.Charset;
public class BloomFilterDemo {
        public static void main(String[] args) {
        /**
         * 创建一个插入对象为一亿,误报率为0.01%的布隆过滤器
         * 不存在一定不存在
         * 存在不一定存在
         * ----------------
         *  Funnel 对象:预估的元素个数,误判率
         *  mightContain :方法判断元素是否存在
         */
        BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")), 100000000, 0.0001);
        bloomFilter.put("死");
        bloomFilter.put("磕");
        bloomFilter.put("Redis");
        System.out.println(bloomFilter.mightContain("Redis"));
        System.out.println(bloomFilter.mightContain("Java"));
    }
}

 具体的解释已经写在注释中了。到这里相信大家一定明白了布隆过滤器和其怎么使用了。

6、实战

我们来模拟这样的场景:通过布隆过滤器来解决缓存穿透。

首先你的知道什么叫缓存穿透吧?

缓存穿透是指用户访问一个缓存和数据库中都没有的数据,因为缓存中不存在,所以就会去访问数据库,如果并发很高。很容易会击垮数据库

那布隆过滤器是如何解决这个问题的呢?他

的原理是这样子的:将数据库中所有的查询条件,放入布隆过滤器中,当一个查询请求过来时,先经过布隆过滤器进行查,如果判断请求查询值存在,则继续查;如果判断请求查询不存在,直接丢弃。

其代码如下:

String get(String key) {
    String value = redis.get(key);     
    if (value  == null) {
        if(!bloomfilter.mightContain(key)){
            return null; 
        }else{
            value = db.get(key); 
            redis.set(key, value); 
        }    
    }
    return value;
}

7、小结

本文详细介绍了布隆过滤器是什么?有什么作用?实现原理以及从代码层面多方面来阐述布隆过滤器。希望能为各位在学习进阶的路上添砖加瓦。

以上就是布隆过滤器面试如何快速判断元素是否在集合里的详细内容,更多关于布隆过滤器面试判断元素是否在集合里的资料请关注脚本之家其它相关文章!

相关文章

  • 解决IDEA中不能正常输入光标变粗的问题

    解决IDEA中不能正常输入光标变粗的问题

    这篇文章主要介绍了在IDEA中不能正常输入光标变粗的解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-09-09
  • Java常用类之System类的使用指南

    Java常用类之System类的使用指南

    System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。本文将通过示例为大家详细讲讲System类的使用,需要的可以参考一下
    2022-07-07
  • Java中char[] 和 String 类型占用字节大小问题

    Java中char[] 和 String 类型占用字节大小问题

    这篇文章主要介绍了Java中char[] 和 String 类型占用字节大小问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • java实现定制数据透视表的示例详解

    java实现定制数据透视表的示例详解

    数据透视表(Pivot Table)是一种数据分析工具,通常用于对大量数据进行汇总、分析和展示,本文主要介绍了如何使用Java将计算项添加到数据透视表中,感兴趣的可以了解下
    2023-12-12
  • iOS获取AppIcon and LaunchImage''s name(app图标和启动图片名字)

    iOS获取AppIcon and LaunchImage''s name(app图标和启动图片名字)

    这篇文章主要介绍了iOS获取AppIcon and LaunchImage's name(app图标和启动图片名字)的相关资料,非常不错,具有参考借鉴价值,感兴趣的朋友一起学习吧
    2016-08-08
  • java正则表达式处理花括号内容替换赋值问题

    java正则表达式处理花括号内容替换赋值问题

    这篇文章主要介绍了java正则表达式处理花括号内容替换赋值问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • Spring Native打包本地镜像的操作方法(无需通过Graal的maven插件buildtools)

    Spring Native打包本地镜像的操作方法(无需通过Graal的maven插件buildtools)

    这篇文章主要介绍了Spring Native打包本地镜像,无需通过Graal的maven插件buildtools,本文探索一下,如果不通过这个插件来生成镜像,结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-02-02
  • JAVA匿名内部类语法分析及实例详解

    JAVA匿名内部类语法分析及实例详解

    这篇文章主要介绍了JAVA匿名内部类语法分析及实例详解,匿名内部类可以使你的代码更加简洁,它与局部类很相似,不同的是它没有类名,如果某个局部类你只需要用一次,那么你就可以使用匿名内部类。对此感兴趣的可以了解一下
    2020-07-07
  • druid return行为方法源码示例解析

    druid return行为方法源码示例解析

    这篇文章主要为大家介绍了druid return行为源码示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • mybatis中实现枚举自动转换方法详解

    mybatis中实现枚举自动转换方法详解

    在使用mybatis的时候经常会遇到枚举类型的转换,下面这篇文章主要给大家介绍了关于mybatis中实现枚举自动转换的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-08-08

最新评论