△Hollis, 一个对Coding有着独特追求的人△

这是Hollis的第 376 篇原创分享

作者 l zyz1992

来源 l Hollis(ID:hollischuang)

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

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

什么叫布隆过滤器

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

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

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

实现原理

先来一张图

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

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

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

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

作用

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

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

使用场景

  • 判断给定数据是否存在

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

具体实现

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

我先来举个例子,假设有旺财和小强两个字符串,他们分别经过三次的 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 ,那是因为其他的数据设置的。

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

代码的实现

作为 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"));}}

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

实战

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

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

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

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

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

其代码如下:

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;}

小结

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

推荐阅读:

25种代码坏味道总结+优化示例

MySQL8.0版本升级建议及各类场景的操作方法

腾讯二面:Redis 事务支持 ACID 么?

缓存和数据库一致性问题,看这篇就够了

搞懂异地多活,看这篇就够了

聊聊分布式锁——Redis和Redisson的方式

看一遍就理解:MVCC原理详解

欢迎关注微信公众号:互联网全栈架构,收取更多有价值的信息。

阿里高频面试题:如何快速判断元素是不是在集合里?相关推荐

  1. 数据库索引高频面试题:java判断文件编码

    二.面试题 面:考你几个红黑树的知识点

  2. 判断两个list集合里的对象某个属性值是否一样_第七章 集合框架

    第一节 集合和数组 1.1 为什么使用集合 数组缺点:长度固定,没有办法动态扩展 集合框架 集合框架简化图 1.2 Collection接口 第二节 List接口 特点:有序.允许重复 有序集合(也称 ...

  3. 腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?

    1.腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中? 思想:用数组来存这40亿个数,而且只能用bit来表示.why? ...

  4. 一道腾讯面试题:如何快速判断某 URL 是否在 20 亿的网址 URL 集合中?布隆过滤器...

    何为布隆过滤器 还是以上面的例子为例: 判断逻辑: 多次哈希: Guava的BloomFilter 创建BloomFilter 最终还是调用: 使用: 算法特点 使用场景 假设遇到这样一个问题:一个网 ...

  5. put url带参数_一道腾讯面试题:如何快速判断某 URL 是否在 20 亿的网址 URL 集合中?...

    来源:http://rrd.me/ekN8q 何为布隆过滤器 还是以上面的例子为例: 判断逻辑: 多次哈希: Guava的BloomFilter 创建BloomFilter 最终还是调用: 使用: 算 ...

  6. 100道Java高频面试题(阿里面试官整理)

    我分享文章的时候,有个读者回复说他去年就关注了我的微信公众号,打算看完我的所有文章,然后去面试,结果我后来很长时间不更新了...所以为了弥补一直等我的娃儿们,给大家的金三银四准备了100道花时间准备的 ...

  7. 2023字节、腾讯、阿里等6家大厂Java开发面试真题+高频面试题总结

    又是一年求职面试旺季,不管你是新进职场小白还是职场老鸟,这些关于java程序员面试应准备的东西你都应该知道. 面试前需要准备 1. Java 八股文:了解常考的题型和回答思路: 2. 算法:刷100- ...

  8. 2020Android大厂高频面试题(字节跳动+阿里+华为+小米等20家大厂面试真题)附面经!

    Android大厂高频面试题 1.        下列哪些语句关于内存回收的说明是正确的? ( )  A. 程序员必须创建一个线程来释放内存   B.内存回收程序负责释放无用内存    C.内存回收程 ...

  9. C++(面试题):给40亿个不重复的无符号整数,没排过序,如何快速判断一个数是否在这40亿个数中

    给40亿个不重复的无符号整数,没排过序,给你一个无符号整数,如何快速判断这个数是否在这40亿个数中? 首先看到这个题第一个想到的就是遍历一遍,看这个数在不在.但是这样的时间复杂度太高了O(N),数据量 ...

  10. 算法面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?

    问题描述:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中? 问题分析:40亿 不重复 ,没有排序. 40亿个unsigned i ...

最新文章

  1. .NET I/O 学习笔记:文件的读和写
  2. Codeforces 285E Positions in Permutations dp + 容斥原理
  3. mysql显示RMB符号乱码_mysql显示乱码
  4. real time linux pdf,【整理】ubuntu real time Linux
  5. 基于外键关联的一对多单向关联
  6. linux虚拟机设置固定IP的方法
  7. componentDidUpdate vs componentWillReceiveProps
  8. crontab周期任务
  9. 苹果零售店被指销售翻新机
  10. 105套抖音快闪模板
  11. 驾照考试之科目三(深圳东周版)
  12. 驾照新规4月起实施:有驾驶经历者可直接申请考试
  13. 微信发红包测试点整理
  14. ubuntu 安装microsoft office
  15. 陈艾盐:春燕百集访谈节目第二十三集
  16. 计算机桌面输入法怎么恢复,电脑桌面系统输入法不见了?输入法不见了找回方法/步骤...
  17. Navicat Premium 12.0.22安装与激活
  18. 我的计算机 桌面图标不见了,我的电脑图标没了,我的电脑不见了的解决方法
  19. 未发表的2015年年终总结
  20. 详解rails命令行

热门文章

  1. biostar handbook(十一)|基因组变异的表示形式
  2. SpringBoot Web开发
  3. 《窈窕绅士》里的诗句
  4. Python学习-安装Anaconda及print我爱王晓静
  5. 12/14 计算器雏形
  6. python_爬校花图片
  7. Windows Server搭建SAN存储服务(iSCSI)
  8. 25张用Photoshop绘制的顶级图片
  9. laravel 清除缓存
  10. 场景二:刮刮卡,大转盘等抽奖算法