Concept
data-structures
概述
布隆过滤器参数m和k的计算公式为m=-(n*ln(p))/ln(2)^2,k=(m/n)*ln(2),并提供Golang实现。
什么是 data-structures
数据结构是计算机存储、组织数据的方式,通过特定逻辑结构(如数组、链表、树)和操作(如增删查改)实现高效的数据处理。布隆过滤器是概率型数据结构的典型代表,用于快速判断元素是否存在。
核心概念
布隆过滤器
- 原理:使用位数组(bit array)和多个哈希函数,将元素映射到位数组的多个位置。
- 参数公式:
m = -(n * ln(p)) / (ln(2))^2n:预期插入元素数量p:目标误判率(如0.01)m:位数组长度
k = (m / n) * ln(2)k:哈希函数数量
- 特性:
- 误判率:可能误判存在(False Positive),但不会漏判(False Negative)。
- 不可逆:不支持删除操作。
典型应用场景
- 缓存穿透防御:快速判断请求数据是否可能存在于缓存中。
- 垃圾邮件过滤:判断邮件地址是否在黑名单中。
- 分布式去重:如大数据量的URL去重(如爬虫)。
- 数据库查询优化:预判数据是否存在,减少磁盘IO。
相关技术
- 概率数据结构:HyperLogLog(基数统计)、Count-Min Sketch(频次估计)。
- 哈希算法:MurmurHash、xxHash(用于生成分布均匀的哈希值)。
- 位操作优化:使用位数组或字节数组模拟位存储,提升空间效率。
- 分布式布隆过滤器:如Redis的BF(Bloom Filter)模块,支持跨节点共享。
学习路径建议
- 基础数据结构:掌握数组、链表、树、哈希表的原理与实现。
- 概率算法入门:学习布隆过滤器、概率论中的哈希碰撞分析。
- 实践实现:
- 用Golang实现布隆过滤器(见下文代码)。
- 调整
m、k参数,观察误判率变化。
- 进阶优化:
- 研究动态扩容策略(如分层布隆过滤器)。
- 探索布隆过滤器在分布式系统中的应用(如Kafka、HBase)。
Golang 实现示例
1package bloom
2
3import (
4 "math"
5 "hash/maphash"
6 "strconv"
7)
8
9// 布隆过滤器
10type BloomFilter struct {
11 bitArray []byte
12 hashSeeds []uint64
13 k int
14 m int
15 n int
16}
17
18// 新建过滤器
19func NewBloom(n int, p float64) *BloomFilter {
20 m := int(-(float64(n) * math.Log(p)) / math.Pow(math.Log(2), 2))
21 k := int(float64(m)/float64(n) * math.Log(2))
22 return &BloomFilter{
23 bitArray: make([]byte, (m+7)/8), // 对齐字节
24 hashSeeds: make([]uint64, k),
25 k: k,
26 m: m,
27 n: n,
28 }
29}
30
31// 添加元素
32func (bf *BloomFilter) Add(element string) {
33 for i, seed := range bf.hashSeeds {
34 h := maphash.Hash{}
35 h.Write([]byte(strconv.Itoa(i) + element))
36 idx := h.Sum64() % uint64(bf.m)
37 bf.bitArray[idx/8] |= 1 << (idx % 8)
38 }
39}
40
41// 检查存在性
42func (bf *BloomFilter) Contains(element string) bool {
43 for i, seed := range bf.hashSeeds {
44 h := maphash.Hash{}
45 h.Write([]byte(strconv.Itoa(i) + element))
46 idx := h.Sum64() % uint64(bf.m)
47 if (bf.bitArray[idx/8] & (1 << (idx % 8))) == 0 {
48 return false
49 }
50 }
51 return true
52}
说明:
- 使用
maphash库生成哈希值,hashSeeds用于区分不同哈希函数。 bitArray以字节数组模拟位数组,通过位操作设置/检查位。- 实际使用中需根据
n和p动态调整m、k。