布隆过滤器介绍
判断目标值是否在一个汇合中是比拟常见的业务场景。在Go语言中通常应用map来实现给性能。然而当汇合比拟大时,应用map会耗费大量的内存。 这种状况下可应用BitMap来代替map。BitMap尽管可能在肯定状况下缩小的内存的耗费,然而BitMap也存在以下局限性:
- 当样本分布极度不平均的时候,BitMap会造成很大空间上的节约。
若数据的类型Int64,并且数据分布的跨度比拟大,则也无奈满足对内存的要求。 - 当元素不是整型的时候,BitMap就不实用了。
BitMap只能保留整形数据,对于字符串类型的数据则不适合应用。
BitMap只能解决整形数据,对于字符串则不能说实用。若可能把字符串映射为整形,就能够应用BitMap来存储字符串的状态了。 hash函数能够将字符串映射为整形数据,然而hash函数映射为整形是存在hash抵触。为了缩小hash抵触,能够应用多个hash函数来将一个字符串映射为多个整数,并将映射后的整数存在BitMap中。在查问字符串时,应用同样的hash函数来计算hash值,并应用同样的hash值来查问BitMap,若其中有一个hash值没有命中,则该url不存在。
上述思路就是布隆过滤器的外围思路。布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的,它实际上是由一个很长的二进制向量和一系列随机映射函数组成,布隆过滤器能够用于检索一个元素是否在一个汇合中。它的长处是空间效率和查问工夫都远远超过个别的算法,毛病是有肯定的误识别率:即布隆过滤器报告某个值存在于BitMap中中,然而实际上该值可能并不在汇合中。然而布隆过滤器若报告某个值不在BitMap中,则该值必定不在汇合中。
缩小布隆过滤器误识别率的办法
布隆过滤器误辨认的起因在于hash抵触,因而缩小hash抵触能够升高布隆过滤器误识别率。hash抵触和BitMap数组的大小以及hash函数的个数以及每个hash函数自身的好坏无关。能够采纳以下办法升高hash抵触的概率:
- 多个hash,增大随机性,缩小hash碰撞的概率。
- 扩充数组范畴,使hash值均匀分布,进一步缩小hash碰撞的概率。
布隆过滤器的Go语言实现
接下来咱们给出布隆过滤器的Go语言实现,目前代码曾经上传到github中,下载地址
定义
首先给出布隆过滤器构造的定义:
type BloomFilter struct { bset *BitMap size uint}
其中:
- BitMap的实现在bitmap.go文件中
- size是BitMap二进制位的数量
创立BloomFilter构造
func NewBloomFilter(size_val ...uint) *BloomFilter { var size uint = 1024*1024 if len(size_val) > 0 && size_val[0] > 0 { size = size_val[0] } bf := &BloomFilter{} bf.bset = NewBitMap(size) bf.size = size return bf}
BloomFilter应用的hash函数
var seeds = []uint{3011, 3017, 3031}func (bf *BloomFilter)hashFun(seed uint, value string) uint64 { hash := uint64(seed) for i := 0; i < len(value); i++ { hash = hash*33 + uint64(value[i]) } return hash}
将数据增加到BloomFilter
func (bf *BloomFilter)Set(value string) { for _, seed := range seeds { hash := bf.hashFun(seed, value) hash = hash % uint64(bf.size) bf.bset.Set(uint(hash)) }}
判断元素是否存在
func (bf *BloomFilter)Check(value string) bool { for _, seed := range seeds { hash := bf.hashFun(seed, value) hash = hash % uint64(bf.size) ret := bf.bset.Check(uint(hash)) if !ret { return false } } return true}