什么是布隆过滤器?
在redis4.0提供了布隆过滤器,简单的来说布隆过滤器就是一个不怎么精确的set结构,当你使用他的contains去判断某个对象是否存在。当布隆器说某个值存在的时候,这个值可能不存在,当他说某个值不存在的时候一定不存在。
布隆过滤器的简单使用
redis
127.0.0.1:6379> bf.add calvinBloom 1
(integer) 1
127.0.0.1:6379> bf.add calvinBloom 2
(integer) 1
127.0.0.1:6379> bf.exists calvinBloom 1
(integer) 1
127.0.0.1:6379> bf.exists calvinBloom 2
(integer) 1
127.0.0.1:6379> bf.exists calvinBloom 3
(integer) 0
python
import redis
import random
client = redis.StrictRedis()
chars = ''.join([chr(ord('a') + i) for i in range(26)])
def random_string(n):
chars_list = []
for i in range(n):
ids = random.randint(0, len(chars) - 1)
chars_list.append(chars[ids])
return ''.join(chars_list)
users = list(set([random_string(64) for i in range(10000)]))
print("total users", len(users))
users_train = users[:int(len(users)/ 2)]
users_test = users[int(len(users) / 2):]
client.delete("codehole")
falses = 0
for user in users_train:
client.execute_command("bf.add", "codehole", user)
print("all train")
for user in users_test:
ret = client.execute_command("bf.add", "codehole", user)
if ret == 1:
falses += 1
print(falses, len(users_test))
从上面的运行的结果看,误判率快接近2%,所以这个误判率还是有点高的。redis中提供了自定参数的布隆过滤器,在bf.add命令前使用bf.reserve创建。bf.reserve有三个参数:key(键),error_rate(错误率),inital_size(预计放入的元素数量)。
注意:
- 如果对应的键已经存在则会报错。
- inital_size如果设置过大会浪费空间,过小则会影响准确率。使用前尽可能估计元素数量,加上一定量的冗余空间来避免实际元素可能高出估计值太多。
布隆过滤器原理
每个布隆过滤器对应到redis数据结构就是一个大型的位数组和几个不一样的hash函数(h1,h2,h3)。当添加的时候,使用多个hash函数对键进行hash,得到一个哈希值,然后对数组的长度进行求余((length-1)& 哈希值)整数s得到一个位置,并将对应的位置设为1。当向布隆过滤器查询键时,和add一样,找到相应的位置,看看是否为1,只要有一个是0,就说明键不存在,反之存在。
空间占用估计
n:预计元素的数量 f:错误率 m:位数组长度 k:哈希函数的最佳数量
k = 0.7*(m/n)
f = 0.6185^(m/n)
从以上公式可以得出:位数组相对越长,错误率越低,hash函数需要的最佳数量也越多(影响判断效率)
这里我直接把redis深度历险书中结论拿出来,推导看下面推荐
推荐阅读
布隆过滤器计算器(结合上面这个推荐理解使用)
布隆过滤器实战【防止缓存击穿】