【布隆过滤器】过滤器中的战斗机

转载请代表出处算法

背景

对 布隆过滤器 画个重点,它应该在 “过滤” 二字上,这个算法的重点在于把曾经来过跟从将来过的事物区分开,具体过滤那种事物(曾经来过or从将来过),由具体场景决定。它通常用于数据库存储中过滤不存在的行(减小访问磁盘),推荐系统去重等等场景。数据库

SET

说到去重,很容易想到STL中的SET容器,它自己自带去重功能,并且还能查询。
那么最简单的方式,直接用SET。每次操做的时候,先查询该事物是否存在?app

  • 若是存在直接返回“存在”结果。
  • 若是不存在就插入其中,而后再返回“不存在”结果。

具体以下图所示:.net

这种方式准确率是绝对准确的,可是这种方式耗费的内存也是巨大的。
假设每一个事物须要 K 字节,那么若是有 M 个事物,一共须要 K * M 字节。那么咱们能不能缩小这里的内存呢?
稍微损失一点准确率换取内存?具体见下面HashMap的方式blog

HashMap

在上一种方式中,它存储了具体的事物信息,其实在咱们这个场景中是不须要的。咱们须要的只是这个事物是否存在就好了,因此HashMap的方式诞生了。
这种算法在每次操做的时候,先查询该事物是否存在,内存

  • 若是存在返回“存在”结果。
  • 若是不存在就在特定位置置1,而后再返回“不存在”结果。

众所周知,hash都是有必定几率冲突的,并且当哈希桶快满的时候,冲突率更高。
接下来咱们来看看这里的冲突率有多少?假设哈希桶长度为M,那么每次插入到特定一个桶的几率是:$$(1-\frac{1}{M})$$
而没有插入特定桶的几率是:$$1-(1-\frac{1}{M})$$
而后假设目前已经插入N个事物,那么特定桶中为0的几率是:$$(1-\frac{1}{M})^N$$
特定桶中为1的几率是:$$1-(1-\frac{1}{M})^N$$get

假设如今要新插入一个事物,此次插入的冲突率就是:hash

\[1-(1-\frac{1}{M})^N = 1- ((1+\frac{1}{-M})^{-M})^{-\frac{N}{M}} \approx 1 - e^{-\frac{N}{M}} \]

因此这里在N接近M的时候,冲突率是很高的,这种算法就彻底失效了。
有没有办法解决这种状况呢?布隆过滤器能下降这里冲突率。class

布隆过滤器

布隆过滤器是用了多hash的方式下降了冲突率的。
这种算法在每次操做的时候,先查询该事物在K个hash桶中是否都存在,容器

  • 若是存在返回“存在”结果。
  • 若是有一个桶不存在,就在K个hash桶中所有置1,而后再返回“不存在”结果。

接下来咱们来看看这种有K个Hash加持的算法,冲突率有多少?假设哈希桶长度为M,那么每次插入到特定一个桶的几率是:$$K (1-\frac{1}{M})$$
而没有插入特定桶的几率是:$$(1-(1-\frac{1}{M}))^K$$
而后假设目前已经插入N个事物,那么特定桶中为0的几率是:$$(1-\frac{1}{M})^{NK}$$
特定桶中为1的几率是:$$1-(1-\frac{1}{M})^{NK}$$
假设如今要新插入一个事物,此次插入的冲突率就是:

\[(1-(1-\frac{1}{M})^{NK})^K= (1- ((1+\frac{1}{-M})^{-M})^{-\frac{NK}{M}} )\approx (1 - e^{-\frac{NK}{M}})^K \]

因为这里有K次方的加持,它的冲突率小不少的。
通常来讲,在使用布隆过滤器的时候,N是由场景已经决定了的,怎么选择M跟K呢?
P为冲突率

\[M=-\frac{NlnP}{(ln2)^2} \]

\[K=\frac{M}{N}ln2 \]

因为布隆过滤器都是直接置1,因此它根本没法删除一个事物的。有没有办法支持它删除+统计个数呢?

布隆过滤器升级版

想要删除特定事物,那其实也很简单。
直接把布隆过滤器的位存储改为数字存储就好了。
那么在每次操做的时候,跟布隆过滤器差异的点在于:

  • 不管是否存在都在K个hash桶中加1,
  • 而后在须要删除的时候,就在K个hash桶中减1。
    具体以下图所示:

这种算法是已经支持删除+统计了,相应的它的内存占用可不是翻倍这么简单的。 不一样的场景用不一样的算法吧,最合适的才是效果最好滴。

相关文章
相关标签/搜索