当前位置:   article > 正文

聊聊布隆过滤器_布隆过滤器使用场景

布隆过滤器使用场景

目录

一、什么是布隆过滤器?

二、使用场景

三、原理

四、使用

4.1、Guava实现

4.2、Redisson实现


一、什么是布隆过滤器

        布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的,是一种数据结构。它实际上是一个很长的二进制向量和一系列随机映射函数

        布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是高效的插入和查询,而且非常节省空间,缺点是hash 碰撞造成的误识别率和删除困难。

二、使用场景

        一般使用较多的场景就是避免缓存穿透,具体场景就是在使用 Reids 做数据缓存的时候,很有可能会遇到一个问题:用户想要查询一个数据,发现 redis 缓存没有命中,于是向数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求数据库。这会给数据库造成很大的压力,这时候就相当于出现了缓存穿透。缓存穿透也是实际开发中必须要避免和提前预防的内容之一。

避免缓存穿透,有以下几种解决方案:
1、缓存空值。为了解决这个问题呢,通常我们可以向分布式缓存中写入一个过期时间较短的空值占位,但这样会占用较多的存储空间,性价比不足。

2、使用 HashMap。将需要查询的 key 提前加载到 HashMap 中,因为 HashMap 查找的时间复杂度为 O(1) ,因此通过映射可以快速查找到相应的 Key 来判定 Key 是否存在 ,如果查不出来就没必要继续查找缓存了。但是这样做的话极其消耗宝贵的内存,数据量大的情况下成本也会上升。此种做法会对内容造成不可测的负担,不推荐使用。

3、使用 Bloom Filter。原理上和使用 HashMap 一样,但更省空间。此种做法为主流做法,推荐使用布隆过滤器。

三、原理

布隆过滤器的原理:当一个元素被加入集合时,通过 K 个散列函数将这个元素映射成一个位数组中的 K 个点,把它们置为 1。检索时,我们只要看看这些点是不是都是 1 就(大约)知道集合中有没有它了:如果这些点有任何一个 0,则被检元素一定不在;如果都是 1,则被检元素很可能在

简单来说就是准备一个长度为 m 的位数组并初始化所有元素为 0,用 k 个散列函数对元素进行 k 次散列运算跟 len (m) 取余得到 k 个位置并将 m 中对应位置设置为 1。

如上图,位数组的长度是8,散列函数个数是 3,先后存入两个元素x,y。这两个元素都经过三次哈希函数生成三个哈希值,并映射到位数组的不同的位置,并置为1。元素 x 映射到位数组的第0位,第4位,第7位,元素y映射到数组的位数组的第1位,第4位,第6位。

保存元素 x 后,位数组的第4位被设置为1之后,在处理元素 y 时第4位会被覆盖,同样也会设置为 1。

当布隆过滤器保存的元素越多被置为 1 的 bit 位也会越来越多,元素 x 即便没有存储过,假设哈希函数映射到位数组的三个位都被其他值设置为 1 了,对于布隆过滤器的机制来讲,元素 x 这个值也是存在的,也就是说布隆过滤器存在一定的误判率

若位数组长度太小则会导致所有 bit 位很快都会被置为 1 ,那么检索任意值都会返回”可能存在“ , 起不到过滤的效果。位数组长度越大,则误判率越小。

同时,哈希函数的个数也需要考量,哈希函数的个数越大,检索的速度会越慢,误判率也越小,反之,则误判率越高。相同位数组长度的情况下,随着哈希函数的个人的增长,误判率显著的下降。

布隆过滤器支持删除吗

布隆过滤器其实并不支持删除元素,因为多个元素可能哈希到一个布隆过滤器的同一个位置,如果直接删除该位置的元素,则会影响其他元素的判断。但我们可以通过计数布隆过滤器(不推荐)定时重新构建布隆过滤器两种方案实现删除元素的效果。

四、使用

4.1、Guava实现

添加Maven依赖

  1. <dependency>
  2. <groupId>com.google.guava</groupId>
  3. <artifactId>guava</artifactId>
  4. <version>22.0</version>
  5. </dependency>
  1. package com.cjian.boomfilter;
  2. import com.google.common.hash.BloomFilter;
  3. import com.google.common.hash.Funnels;
  4. import java.nio.charset.StandardCharsets;
  5. /**
  6. * @Author: cjian
  7. * @Date: 2023/4/20 11:53
  8. * @Des:
  9. */
  10. public class Demo {
  11. static BloomFilter<String> filter;
  12. static {
  13. filter = BloomFilter.create(
  14. //Funnel 是一个接口,用于将任意类型的对象转换为字节流,
  15. //以便用于布隆过滤器的哈希计算。
  16. Funnels.stringFunnel(StandardCharsets.ISO_8859_1),
  17. 10000, // 插入数据条目数量
  18. 0.001 // 误判率
  19. );
  20. addDate();
  21. }
  22. public static void main(String[] args) {
  23. System.out.println(mayContain("aaa"));
  24. System.out.println(mayContain("bbb"));
  25. }
  26. private static void addDate() {
  27. System.out.println("初始化布隆过滤器数据开始");
  28. //插入2个元素
  29. filter.put("aaa");
  30. filter.put("bbb");
  31. System.out.println("初始化布隆过滤器数据结束");
  32. }
  33. public static boolean mayContain(String id) {
  34. return filter.mightContain(id);
  35. }
  36. }

4.2、Redisson实现

添加Maven依赖 

  1. <dependency>
  2. <groupId>org.redisson</groupId>
  3. <artifactId>redisson</artifactId>
  4. <version>3.16.1</version>
  5. </dependency>
  1. package com.cjian.boomfilter;
  2. import org.redisson.Redisson;
  3. import org.redisson.api.RBloomFilter;
  4. import org.redisson.api.RedissonClient;
  5. import org.redisson.config.Config;
  6. /**
  7. * @Author: cjian
  8. * @Date: 2023/4/20 13:54
  9. * @Des:
  10. */
  11. public class RedissonDemo {
  12. static RBloomFilter<String> bloomFilter;
  13. static {
  14. Config config = new Config();
  15. config.useSingleServer().setAddress("redis://localhost:6379");
  16. bloomFilter = Redisson.create(config).getBloomFilter("myBloomFilter");
  17. }
  18. public static void main(String[] args) {
  19. init();
  20. System.out.println(mightContain("aaaa"));
  21. System.out.println(mightContain("bbbb"));
  22. }
  23. private static void init() {
  24. //10000表示插入元素的个数,0.001表示误判率
  25. bloomFilter.tryInit(10000, 0.001);
  26. //插入2个元素
  27. bloomFilter.add("aaaa");
  28. bloomFilter.add("bbbb");
  29. }
  30. private static boolean mightContain(String id) {
  31. return bloomFilter.contains(id);
  32. }
  33. }

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号