布隆过滤器(Bloom Filter)原理以及Go语言实现

布隆过滤器介绍

判断目标值是否在一个集合中是比较常见的业务场景。在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
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go lang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值