RedisBloom 模块为 Redis 提供了 Bloom Filter 数据结构,除了基本的创建、添加、查询等操作外,还提供了用来导出单个过滤器的 BF.SCANDUMP 命令,和导入命令 BF.LOADCHUNK。
官方文档 Example
Syntax
BF.SCANDUMP key iterator
iterator 参数初始值为 0,表示从头开始导出,命令返回两个元素的数组:
- 下一个迭代器值,如果再次为 0 则表示导出完成
- 导出的数据块
BF.LOADCHUNK key iterator data
Examples
redis> BF.RESERVE bf 0.1 10
OK
redis> BF.ADD bf item1
1) (integer) 1
redis> BF.SCANDUMP bf 0
1) (integer) 1
2) "\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x02\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x9a\x99\x99\x99\x99\x99\xa9?J\xf7\xd4\x9e\xde\xf0\x18@\x05\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x00"
redis> BF.SCANDUMP bf 1
1) (integer) 9
2) "\x01\b\x00\x80\x00\x04 \x00"
redis> BF.SCANDUMP bf 9
1) (integer) 0
2) ""
redis> DEL bf
(integer) 1
redis> BF.LOADCHUNK bf 1 "\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x02\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x9a\x99\x99\x99\x99\x99\xa9?J\xf7\xd4\x9e\xde\xf0\x18@\x05\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x00"
OK
redis> BF.LOADCHUNK bf 9 "\x01\b\x00\x80\x00\x04 \x00"
OK
redis> BF.EXISTS bf item1
(integer) 1
chunks = []
iter = 0
while True:
iter, data = BF.SCANDUMP(key, iter)
if iter == 0:
break
else:
chunks.append([iter, data])
# Load it back
for chunk in chunks:
iter, data = chunk
BF.LOADCHUNK(key, iter, data)
可用于布隆过滤器数据迁移的 Python 脚本
Conda Env
$ conda create -n redisbloom python=3.12
$ conda activate redisbloom
$ pip install redis[hiredis]
$ pip list
Package Version
---------- -------
hiredis 3.3.0
pip 25.2
redis 7.0.1
setuptools 80.9.0
wheel 0.45.1
备份脚本
redis_bloom_backup.py:
import redis
import pickle
import argparse
def backup(key):
r = redis.Redis(host='localhost', port=6379)
chunks = []
iter = 0
while True:
iter, data = r.bf().scandump(key, iter)
if iter == 0:
break
else:
chunks.append([iter, data])
with open(f"dump_{key}.pkl", 'wb') as file:
pickle.dump(chunks, file)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="SCANDUMP bloom filter to a file.")
parser.add_argument("key", type=str, help="Key of bloom filter")
args = parser.parse_args()
backup(args.key)
$ python redis_bloom_backup.py "test:restore"
$ $ ls -alh dump_test:restore.pkl
-rw-rw-r-- 1 root root 2.1G 11月 8 15:51 dump_test:restore.pkl
即使未向过滤器中插入数据,创建好指定容量的过滤器后,导出时,数据文件也是 BF.INFO 的 Size 大小。
恢复脚本
redis_bloom_restore.py:
import redis
import pickle
import argparse
def restore(dump_file, key):
r = redis.Redis(host='localhost', port=6379)
with open(dump_file, 'rb') as file:
chunks = pickle.load(file)
for chunk in chunks:
iter, data = chunk
r.bf().loadchunk(key, iter, data)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="LOADCHUNK bloom filter from a file.")
parser.add_argument("dump_file", type=str, help="Dump file of bloom filter")
parser.add_argument("key", type=str, help="Key of bloom filter")
args = parser.parse_args()
restore(args.dump_file, args.key)
$ python redis_bloom_restore.py dump_test:restore.pkl tmpbf
$ redis-cli bf.info tmpbf
1) Capacity
2) (integer) 1000000000
3) Size
4) (integer) 2157872304
5) Number of filters
6) (integer) 1
7) Number of items inserted
8) (integer) 999973866
9) Expansion rate
10) (integer) 2
导入时,不能提前创建过滤器,否则会报错,直接向不存在的 key 中导入即可。