Python Counting Bloom Filter原理与实现详细介绍

作者:木东居士 时间:2021-04-04 19:01:54 

前言

标准的 Bloom Filter 是一种比较简单的数据结构,只支持插入和查找两种操作。在所要表达的集合是静态集合的时候,标准 Bloom Filter 可以很好地工作,但是如果要表达的集合经常变动,标准Bloom Filter的弊端就显现出来了,因为它不支持删除操作。这就引出来了本文要谈的 Counting Bloom Filter,后文简写为 CBF。

原理

一、BF 为什么不支持删除

BF 为什么不能删除元素?我们可以举一个例子来说明。

比如要删除集合中的成员 dantezhao,那么就会先用 k 个哈希函数对其计算,因为 dantezhao 已经是集合成员,那么在位数组的对应位置一定是 1,我们如要要删除这个成员 dantezhao,就需要把计算出来的所有位置上的 1 置为 0,即将 5 和 16 两位置为 0 即可。

Python Counting Bloom Filter原理与实现详细介绍

问题来了!现在,先假设 yyj 本身是属于集合的元素,如果需要查询 yyj 是否在集合中,通过哈希函数计算后,我们会去判断第 16 和 第 26 位是否为 1, 这时候就得到了第 16 位为 0 的结果,即 yyj 不属于集合。 显然这里是误判的。

二、什么是 Counting Bloom Filter

Counting Bloom Filter 的出现,解决了上述问题,它将标准 Bloom Filter 位数组的每一位扩展为一个小的计数器(Counter),在插入元素时给对应的 k (k 为哈希函数个数)个 Counter 的值分别加 1,删除元素时给对应的 k 个 Counter 的值分别减 1。Counting Bloom Filter 通过多占用几倍的存储空间的代价, 给 Bloom Filter 增加了删除操作。基本原理是不是很简单?看下图就能明白它和 Bloom Filter 的区别在哪。

Python Counting Bloom Filter原理与实现详细介绍

三、Counter 大小的选择

CBF 和 BF 的一个主要的不同就是 CBF 用一个 Counter 取代了 BF 中的一位,那么 Counter 到底取多大才比较合适呢?这里就要考虑到空间利用率的问题了,从使用的角度来看,当然是越大越好,因为 Counter 越大就能表示越多的信息。但是越大的 Counter 就意味着更多的资源占用,而且在很多时候会造成极大的空间浪费。

因此,我们在选择 Counter 的时候,可以看 Counter 取值的范围多小就可以满足需求。

根据论文中描述,某一个 Counter 的值大于或等于 i 的概率可以通过如下公式描述,其中 n 为集合的大小,m 为 Counter 的数量,k 为 哈希函数的个数。

Python Counting Bloom Filter原理与实现详细介绍

在之前的文章《Bloom Filter 的数学背景》中已经得出,k 的最佳取值为 k = m/n * ln2,将其带入公式后可得。

Python Counting Bloom Filter原理与实现详细介绍

如果每个 Counter 分配 4 位,那么当 Counter 的值达到 16 时就会溢出。这个概率如下,这个值足够小,因此对于大多数应用程序来说,4位就足够了。

Python Counting Bloom Filter原理与实现详细介绍

关于 CBF 中 Counter 大小的选择,主要参考这篇论文:《Summary Cache: A Scalable Wide-Area Web Cache Sharing Protocol》,在论文的第 6、7 两页专门对其做了一番阐述。这里不再推导细节,只给出一个大概的说明,感兴趣的童鞋可以参考原论文。

简单的实现

还是实现一个简单的程序来熟悉 CBF 的原理,这里和 BF 的区别有两个:

  • 一个是我们没有用 bitarray 提供的位数组,而是使用了 bytearray 提供的一个 byte数组,因此每一个 Counter 的取值范围在 0~255。

  • 另一个是多了一个 remove 方法来删除集合中的元素。

代码很简单,只是为了理解概念,实际中使用的库会有很大差别。

import mmh3
class CountingBloomFilter:
   def __init__(self, size, hash_num):
       self.size = size
       self.hash_num = hash_num
       self.byte_array = bytearray(size)
   def add(self, s):
       for seed in range(self.hash_num):
           result = mmh3.hash(s, seed) % self.size
           if self.bit_array[result] < 256:
               self.bit_array[result] += 1
   def lookup(self, s):
       for seed in range(self.hash_num):
           result = mmh3.hash(s, seed) % self.size
           if self.bit_array[result] == 0:
               return "Nope"
       return "Probably"
   def remove(self, s):
       for seed in range(self.hash_num):
           result = mmh3.hash(s, seed) % self.size
           if self.bit_array[result] > 0:
               self.bit_array[result] -= 1
cbf = CountingBloomFilter(500000, 7)
cbf.add("dantezhao")
cbf.add("yyj")
cbf.remove("dantezhao")
print (cbf.lookup("dantezhao"))
print (cbf.lookup("yyj"))

来源:https://cloud.tencent.com/developer/article/1136056

标签:Python,Counting,Bloom,Filter
0
投稿

猜你喜欢

  • python中lambda()的用法

    2022-07-19 05:15:45
  • python中matplotlib的颜色及线条控制的示例

    2023-11-04 08:11:50
  • selenium环境搭建及基本元素定位方式详解

    2021-12-09 14:53:33
  • JupyterLab远程密码访问实现

    2022-06-04 23:52:26
  • php基于curl主动推送最新内容给百度收录的方法

    2023-11-22 04:46:44
  • Pycharm在指定目录下生成文件和删除文件的实现

    2022-04-12 20:00:28
  • python暴力解压rar加密文件过程详解

    2023-11-20 06:28:38
  • pycharm不以pytest方式运行,想要切换回普通模式运行的操作

    2022-02-05 15:27:10
  • Python实现的根据文件名查找数据文件功能示例

    2022-05-13 17:47:40
  • Golang中的sync.WaitGroup用法实例

    2023-08-31 03:57:28
  • python数据预处理 :样本分布不均的解决(过采样和欠采样)

    2023-08-10 07:03:14
  • python反转(逆序)字符串的6种方法详细

    2023-03-14 10:38:41
  • Python实现针对中文排序的方法

    2022-04-20 23:21:51
  • js实现浏览器倒计时跳转页面效果

    2023-07-18 06:49:57
  • python GUI库图形界面开发之PyQt5单选按钮控件QRadioButton详细使用方法与实例

    2022-01-26 01:33:47
  • Python抽象类的新写法

    2022-12-04 13:39:38
  • 网页模式化窗口

    2008-04-27 20:52:00
  • python画条形图实例

    2023-12-04 12:32:33
  • Oracle 9i产品文档

    2010-07-16 13:35:00
  • Python基础面向对象之继承与派生详解

    2022-04-20 11:58:53
  • asp之家 网络编程 m.aspxhome.com