【数据结构】布隆过滤器

慈云数据 12个月前 (03-23) 技术支持 57 0
SueWakeup

                                                     个人主页:SueWakeup

                                                     系列专栏:学习技术栈

                                                     个性签名:保留赤子之心也许是种幸运吧

本文封面由 凯楠📸 友情提供

目录

本栏传送门 

前言

1. 什么是布隆过滤器? 

2. 布隆过滤器的原理 

2.2 判断元素存在原理

3. 布隆过滤器使用场景 

4. 使用 Java 语言实现布隆过滤器 

测试用例

测试结果

注:手机端浏览本文章可能会出现 “目录”无法有效展示的情况,请谅解,点击侧栏目录进行跳转 


本栏传送门 

1.【技术栈】Redis 的理解与数据存储格式

2.【技术栈】Redis 中的事务及持久化方式

3.【技术栈】Redis 删除策略

4.【技术栈】Redis 企业级解决方案

5.【数据结构】布隆过滤器

6.【开发】SpringBoot 整合 Redis

7.【技术栈】Spring Cache 简化 Redis 缓存使用


前言

        在使用 Redis 作缓存时,可能出现 “缓存穿透(对不存在于Redis的数据发起请求,恶意或者误操作地使得大量的请求穿透缓存直接访问数据库,导致数据库压力过大)” 问题。为了防止 Redis 缓存穿透,可以使用 “布隆过滤器” 避免大量不存在的 key 直接访问数据库。


1. 什么是布隆过滤器? 

布隆过滤器(Bloom Filter)是由 Burton Howard Bloom 于 1970 年提出的 “位数组” 和 “一组哈希函数” 两部分组成,用于检查元素是否存在于指定集合中的数据结构。

  • 优点:高效且性能很好。

            位数组中的每个元素都只占用 1 bit,并且每个元素只能是 0 或者 1。申请 100w 个元素的位数组只占用 1000000 Bit / 8 = 125000 字节 = 125000字节 / 1024 ≈ 122 字节 的空间。

    • 缺点:具有一定的误判性(错误识别率)和删除难度。理论情况下,添加到集合中的元素越多,误判的可能性越大。

      2. 布隆过滤器的原理 

      2.1 添加元素原理

      1. 使用布隆过滤器中的哈希函数对元素值进行计算,得到哈希值(哈希值为多个)。
      2. 根据得到的哈希值,在位数组中把对应下标的值 “置为1”。

      2.2 判断元素存在原理

      1. 对给定元素再次进行相同的哈希计算。
      2. 得到值之后判断位数组中的每个元素是否都为 1,如果都为 1,则说明这个元素可能存在于布隆过滤器中,如果存在一个值不为 1,说明该元素不在布隆过滤器中。

      为什么说 “位数组” 中的每个元素都为1,这个元素可能存在于布隆过滤器中?

      • 一方面,判断元素存在需要对给定元素进行哈希计算,哈希计算的 “范围” 受 Integer 的MIN_VALUE(-2 ^ 31) 和 MAX_VALUE(2 ^ 31 - 1)影响,范围有限,不同的元素的哈希计算可能出现同一个哈希值。
      • 另一方面,在布隆过滤器 “添加元素” 时,我们会对给定元素进行多次哈希计算避免 “哈希冲突(哈希函数计算得到相同的哈希码)”,所以,两个不同的元素分别进行多次哈希计算,某次计算的哈希码在位数组的指向可能为同一个位置(如图所示)。

        • 故,位数组中的每个元素都为1,这个元素可能存在于布隆过滤器中。
        • 但是,都不为1,这个元素肯定不存在于布隆过滤器中。

          这个说法,在后文中 “使用 Java 语言实现布隆过滤器” 有体现


          3. 布隆过滤器使用场景 

          • 判断给定数据是否存在:  
            • 判断一个数字是否存在于 “包含大量数字” 的数字集合中(5 亿)。
            • 防止 “缓存穿透”(判断请求的数据是否有效避免直接绕过缓存请求数据库)。
            • 邮箱的垃圾邮件过滤、黑名单功能等。
          • 去重
            • 爬虫程序对已经爬取过的 URL 去重。

            4. 使用 Java 语言实现布隆过滤器 

            思路:

            1. 一个合适大小的位数组保存数据。
            2. 几个不同的哈希函数。
            3. 添加元素到位数组(布隆过滤器)的方法实现。
            4. 判断给定元素是否存在于位数组(布隆过滤器)的方法实现。
            public class MyBloomFilter {
                // ①位数组的长度
                private static final int DEFAULT_SIZE = 2 >16)));
                    }
                }
            }

            测试用例

            public class BloomFilterTest {
                public static void main(String[] args) {
                    MyBloomFilter myBloomFilter = new MyBloomFilter();
                    myBloomFilter.add(131);
                    myBloomFilter.add(110);
                    myBloomFilter.add(120);
                    myBloomFilter.add(119);
                    myBloomFilter.add(114);
                    System.out.println(myBloomFilter.contains(112));
                }
            }

            测试结果

            {2, 129, 130, 131}
            {2, 36, 40, 66, 98, 106, 108, 129, 130, 131}
            {2, 32, 36, 40, 56, 66, 80, 98, 106, 108, 112, 120, 129, 130, 131}
            {2, 32, 36, 37, 40, 49, 56, 66, 80, 82, 98, 106, 108, 112, 114, 115, 117, 120, 129, 130, 131}
            {2, 32, 36, 37, 40, 48, 49, 56, 66, 80, 82, 98, 106, 108, 112, 114, 115, 117, 120, 129, 130, 131}
            true

            在此, “位数组” 中的每个元素都为1,这个元素可能存在于布隆过滤器中的说法 得到了验证。

微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon