import mmh3 import redis import mathclass PyBloomFilter:# 内置100个随机种子SEEDS = [543, 460, 171, 876, 796, 607, 650, 81, 837, 545, 591, 946, 846, 521, 913, 636, 878, 735, 414, 372,344, 324, 223, 180, 327, 891, 798, 933, 493, 293, 836, 10, 6, 544, 924, 849, 438, 41, 862, 648, 338,465, 562, 693, 979, 52, 763, 103, 387, 374, 349, 94, 384, 680, 574, 480, 307, 580, 71, 535, 300, 53,481, 519, 644, 219, 686, 236, 424, 326, 244, 212, 909, 202, 951, 56, 812, 901, 926, 250, 507, 739, 371,63, 584, 154, 7, 284, 617, 332, 472, 140, 605, 262, 355, 526, 647, 923, 199, 518]def __init__(self, capacity=2000000000, error_rate=0.00000001, conn=None, key='BloomFilter'):""" 初始化布隆过滤器。:param capacity: 预先估计要去重的数量。:param error_rate: 错误率。:param conn: Redis 的连接客户端。:param key: 在 Redis 中键的名字前缀。""" self.m = math.ceil(capacity * math.log2(math.e) * math.log2(1 / error_rate)) # 需要的总 bit 数self.k = 1 # 需要最少的 hash 次数self.mem = math.ceil(self.m / 8 / 1024 / 1024) # 需要的多少 M 内存self.block_size_gb = 10 # 每个内存块的大小(GB)self.block_size_bits = self.block_size_gb * 1024 * 1024 * 8 # 每个内存块的大小(bits)self.blocknum = min(math.ceil(self.mem / self.block_size_gb), 256) # 需要多少个 10GB 的内存块self.seeds = self.SEEDS[:self.k] # 只需要一个种子用于单哈希self.key = keyself.N = 2 ** 31 - 1self.redis = connprint("self.m", self.m)print("self.k", self.k)print("self.mem", self.mem)print("self.block_size_bits", self.block_size_bits)print("self.blocknum", self.blocknum)print("self.seeds", self.seeds)def add(self, value):""" 将元素添加到布隆过滤器中。:param value: 要添加的元素。""" # 计算 Redis 键名name = f"{self.key}_{ord(value[0]) % self.blocknum}"# 获取哈希值列表hashs = self.get_hashes(value)# 设置每个哈希位置的位为 1for hash in hashs:block_index = hash // self.block_size_bitsbit_offset = hash % self.block_size_bitsblock_name = f"{name}_{block_index}"self.redis.setbit(block_name, bit_offset, 1)def is_exist(self, value):""" 检查元素是否存在于布隆过滤器中。:param value: 要检查的元素。:return: 如果存在返回 True,否则返回 False。""" # 计算 Redis 键名name = f"{self.key}_{ord(value[0]) % self.blocknum}"# 获取哈希值列表hashs = self.get_hashes(value)exist = True# 检查每个哈希位置的位是否为 1for hash in hashs:block_index = hash // self.block_size_bitsbit_offset = hash % self.block_size_bitsblock_name = f"{name}_{block_index}"exist = exist and bool(self.redis.getbit(block_name, bit_offset))return existdef get_hashes(self, value):""" 获取元素的哈希值列表。:param value: 要哈希的元素。:return: 哈希值列表。""" hashs = list()for seed in self.seeds:hash_value = mmh3.hash(value, seed)if hash_value >= 0:hashs.append(hash_value)else:hashs.append(self.N - hash_value)return hashs# 创建 Redis 连接池 pool = redis.ConnectionPool(host='127.0.0.1', port=6379, db=8) # 创建 Redis 客户端 conn = redis.Redis(connection_pool=pool) # 创建布隆过滤器实例 bf = PyBloomFilter(conn=conn)# 测试添加元素和检查元素是否存在 bf.add("example") print(bf.is_exist("example")) # 存在 输出应为 True print(bf.is_exist("test")) # 不存在 输出应为 False
去重方式有那些
1. 数据库 唯一索引
比如MySQL,es等
2. redis set
3. 布隆过滤器
4. 时间 + redis set
5.