简介
布隆过滤器(Bloom Filter)是一种用于快速判断一个元素是否属于一个集合的概率型数据结构。它通过使用位数组(bit array)和一系列哈希函数来实现。它通常被应用到redis中来防止缓存穿透。一些redis客户端往往实现了默认的布隆过滤器。
基本原理
布隆过滤器的基本原理如下:
- 初始化:创建一个包含 m 个位的位数组,所有位都初始化为 0。
- 添加元素:当要向布隆过滤器中添加一个元素时,将该元素经过一系列哈希函数的计算,得到多个哈希值。然后将位数组中对应的这些位都设置为 1。
- 查询元素:当要查询一个元素是否存在于布隆过滤器中时,将该元素经过相同的一系列哈希函数的计算,得到多个哈希值。然后检查位数组中对应的这些位,如果其中有任何一个位为 0,则可以确定该元素一定不存在于集合中;如果所有位都为 1,则表示该元素可能存在于集合中,但并不能确定一定存在,可能存在一定的误判率。
需要注意的是,布隆过滤器中的哈希函数往往不是一个而是多个,哈希函数越多,误判的概率也会越小,但是通用也会影响其性能。
Golang实现
以下是一个简单的Golang实现的布隆过滤器实例,大概介绍了布隆过滤器的工作原理,与实际应用的布隆过滤器有一定差异:
package main
import (
"fmt"
"hash/fnv"
"math"
)
type BloomFilter struct {
bitSet []bool
hashers []hasher
}
type hasher interface {
hash(data []byte) uint32
}
type fnvHasher struct {
}
func (h *fnvHasher) hash(data []byte) uint32 {
hash := fnv.New32()
hash.Write(data)
return hash.Sum32()
}
// size表示位空间大小,numHashers表示哈希函数的个数
func NewBloomFilter(size int, numHashers int) *BloomFilter {
return &BloomFilter{
bitSet: make([]bool, size),
hashers: generateHashers(numHashers),
}
}
func (bf *BloomFilter) Add(data []byte) {
for _, h := range bf.hashers {
index := h.hash(data) % uint32(len(bf.bitSet))
bf.bitSet[index] = true
}
}
func (bf *BloomFilter) Contains(data []byte) bool {
for _, h := range bf.hashers {
index := h.hash(data) % uint32(len(bf.bitSet))
if !bf.bitSet[index] {
return false
}
}
return true
}
func generateHashers(count int) []hasher {
hashers := make([]hasher, count)
for i := 0; i < count; i++ {
hashers[i] = &fnvHasher{}
}
return hashers
}
func main() {
bf := NewBloomFilter(1000, 3)
data1 := []byte("apple")
data2 := []byte("banana")
data3 := []byte("orange")
bf.Add(data1)
bf.Add(data2)
fmt.Println(bf.Contains(data1)) // Output: true
fmt.Println(bf.Contains(data2)) // Output: true
fmt.Println(bf.Contains(data3)) // Output: false
}
总结
由于布隆过滤器使用的是位数组和哈希函数,所以它具有高效的插入和查询操作,并且占用的空间相对较小。但是它也存在一定的缺点,即有一定的误判率。当要查询的元素不存在于集合中时,由于哈希函数的碰撞,有可能会导致某些位被错误地设置为 1,从而判断该元素存在于集合中。因此,布隆过滤器适用于那些可以容忍一定误判率的场景,例如缓存、垃圾邮件过滤等。
布隆过滤器同时也很难做删除操作。假设有两个key,分别是key1和key2,他们经过一系列的hash之后得到了相同的hash值,那么如果要删除key1的话,也会将key2也删除掉,这种由哈希碰撞带来的影响同时也会影响到删除操作。
总的来说,布隆过滤器是一种概率型数据结构,用于快速判断一个元素是否属于一个集合。它通过位数组和哈希函数实现高效的插入和查询操作,但存在一定的误判率。