Skip to content

布隆过滤器

1074字约4分钟

大数据

2024-03-12

使用场景

布隆过滤器主要的使用场景是用于 快速判断一个元素是否在一个集合之中. 通常用于过滤海量的数据请求以及提高对于数据的查找效率. 例如刷抖音的时候, 想要判断该视频是否已经被当前用户所收藏就是一个判断某元素是否在一个集合的问题, 我们可以使用布隆过滤器来提高查询的效率.

布隆过滤

布隆过滤器是一种具有空间优势的概率数据结构, 核心就是一个超大的位数组和哈希函数, 用于回答一个元素是否存在于一个集合中这样的问题, 但是可能会出现误判——即一个元素不在集合但被认为在集合中.

布隆过滤基本原理

  1. 给定长度为 N 个 bits 的哈希空间.
  2. 选取 d 个哈希函数, 每个哈希函数将给定的元素映射到 [0, N-1] 的一个位置上, 并将该位置为 1.
  3. 将需要被判断的元素也用 2 中的 d 个哈希函数算出 d 个位置 a1, a2,..., ad
  4. 如果 a1, a1,..., ad 对应的位有一个不为 1, 则该元素一定不在集合中.
  5. 如果 a1, a1,..., ad 对应的位全为 1, 则该元素可能存在于集合中.
布隆过滤基本原理
布隆过滤基本原理

从上面可以看出, 一个布隆过滤器应该起码有以下参数:

  1. 哈希空间大小, 记为m. 以上示例中 m = 20 bits;
  2. 元素集合大小, 记为n. 以上示例中 n = 2;
  3. 哈希函数个数, 记为k. 以上示例中 k = 2;
  4. 因为 BF 是 Allowable Errors 的, 可能会出现一个元素原本不在集合中, 但是被错判为存在于集合中, 这个错判的概率叫 false postive, 记为ε

错误率最小, 各个参数之间的关系:

k=mnln2k = \frac{m}{n} \ln2

m=nlnϵ(ln2)2m = - \frac{n \ln \epsilon}{{\left( \ln 2 \right)}^2 }

mn=log2ϵln21.44log2ϵ\frac{m}{n}=- \frac{\log_2 \epsilon}{\ln 2} \approx -1.44 \log_2 \epsilon

如何选择哈希函数-murmur3

从概率计算和速度角度, 哈希函数需满足:

1)独立、均匀分布.

2)计算速度快.

优缺点

优点: 内存效率高、查询速度快、可并行处理;

缺点: 误判率, 主要取决于哈希函数的数量和位数组的大小, 哈希冲突;不支持删除、不能获取原始数据, 误判率.

优化: 较大的位数组可以降低误判率, 但会增加内存消耗, 因此需要权衡.

应用

数据库防止穿库. 使用 BloomFilter 来减少不存在的行或列的磁盘查找. 避免代价高昂的磁盘查找会大大提高数据库查询操作的性能.

业务场景中判断用户是否阅读过某视频或文章, 比如抖音或头条, 当然会导致一定的误判, 但不会让用户看到重复的内容.

m, k := bloom.EstimateParameters(uint(len(md)), 0.001)
filter := bloom.New(m, k)
for d := range md {
    if len(d) == 0 {
        continue
    }
    filter.Add([]byte(d))
}
if filter.Test([]byte(d)) {
    fmt.print("数据存在!")
}

性能比较

输入数据量 0.01Bloom 内存/ CPU 峰值map 内存/ CPU 峰值内存节省
1w0.8MB1.18MB32.5%
5w1.5MB3.3MB54.5%
10w1.37MB3.66MB62%
50w2.24MB23.2MB90%
100w2.7MB46.1MB94%
500w9.3MB191.4MB95%
1000w17.6MB382.5MB95%
5000w61.7MB1705.2MB96%

内存占用 Bloom 减少 60%-90% 的内存占用

全量插入 + 全量查询, 耗时记录:

输入数据量 0.01Bloom 查询耗时map 查询耗时耗时增加
1w1+1=2ms508+508=1ms200%
5w5.6+4.8=10.5ms3.2+3.0=6.3ms166%
10w12+9.6=21.8ms9+6=15ms145%
50w61.1+52.1=113.2ms51.6+47.6=99.1ms114%
100w125.9+109.4=235.3ms136.5+121.5=258ms91%
500w665.5+592=1.26s723.5+711.8=1.4s90%
1000w1.87+1.5=3.9s1.48+1.4=2.9s134%
3000w16.5s9.8s168%
5000w15+13=28s7.6+7.6=15.2s184%




变更历史

最后更新于: 查看全部变更历史
  • docs: update docs

    于 2024/11/19
  • 整理图片和文章

    于 2024/11/7
  • 整理文章代码格式

    于 2024/11/1
  • 整理文章格式

    于 2024/11/1
  • update

    于 2024/10/17
  • 新增文字+CRLF全部替换为LF

    于 2024/10/17
  • 升级主题+新增文章+修改格式

    于 2024/10/14
  • 升级版本+规整文档中的格式

    于 2024/10/11
  • 整理图片格式和名称(not finished)

    于 2024/9/30
  • 给予文件夹顺序

    于 2024/9/24
  • 调整博客分类+修改about-me.md

    于 2024/9/24
  • first commit

    于 2024/9/20