(高阶) Redis 7 第15讲 布隆过滤器 BitMap篇

布隆过滤器是一种高效的数据结构,用于判断元素是否可能存在。它利用多个哈希函数将元素映射到位数组中,判断时通过检查位数组来推测元素存在性。虽然存在误判风险,但能有效防止缓存穿透。Redis中的Bitmap同样适用于快速标记状态,常用于黑名单校验、网站判断等场景。实现时需初始化位数组,并根据哈希值设置和检查位。当元素过多时,需考虑重构过滤器。

面试题

如何快速准备判断某一数据在海量数据中存在
了解布隆过滤器吗
安全网址判断,黑名单校验,识别垃圾邮件
白名单校验,识别合法用户?

理论

由一个初始值都为0的 bit数组和多个哈希函数构成,用来快速判断集合中是否存在某个元素 

设计思想

目的减少内存占用
方式不保存数据信息,只是在内存中做一个是否存在的标记flag

 判断具体数据是否存在于一个大集合中

特点

         高效的插入和查询,占用空间少,返回的结果是不确定性和不够完美。

一个元素如果判断结果存在时,元素不一定存在,但是判断为不存在时一定不存在。(总结:有是可能有;无是肯定无)

        布隆过滤器可以添加元素,但是不能删除元素,涉及到hashcode判断依据,删除元素会到处误判率增加。

原理

 布隆过滤器(Bloom Filter)是一种专门用来解决去重问题的高级数据结构。

实际就是一个大型位数组和几个不同的无偏hash函数(无偏表示分布均匀)。由一个初始值为0的bit数组和多个哈希函数构成,用来快速判断某个数据是否存在。但是跟HyperLogLog一样,也存在不精确,存在误差。

添加KEY

         使用多个 Hash 函数对key进行hash算法得到一个整数索引值,对位数组长度进行取模运算得到一个位置,每个Hash 函数都会得到一个不同的位置,将几个位置都置则完成添加操作。

查询KEY

        只要有一位是 0,则表示 key 不能存在;如果都是 1,则不一定存在对应的key。

数据不精确

        Hash 冲突导致数据不精确

当有变量加入集合时,通过N个映射函数将变量映射成位图中的N个点,把它们都置为1 

 查询某个变量只要看这些点是不是都是 1,就可以大概率知道集合中有没有它
如果这些点有任何一个为零则被查询变量一定不在,如果都是 1,则被查询变量很可能存

 哈希函数

        将任意大小的输入数据转换成特定大小的输出数据的函数,转换后的数据称为哈希值或哈希编码,也叫散列值 

        散列函数的输入和输出不是唯一对应关系,如果两个散列值相同,两个输入值可能相同可能不同(如下图中的56E5RD),这种情况叫做‘散列碰撞(collision)’

优势 

  • 正是基于布隆过滤器的快速检测特性,在把数据写入数据库时,使用布隆过滤器做个标记。
  • 当缓存缺失后,查询数据库时,通过查询布隆过滤器快速判断数据是否存在。
  • 如果不存在,就不再去数据库中查询,即使发生缓存穿透,大量请求只会查询Redis和布降过滤器,而不会积压到数据库,就不会影响数据库的正常运行。
  • 布隆过滤器可以使用Redis实现,本身就能承担较大的并发访问压力。

使用步骤 

        1. 初始化 bitmap:由长度为m的位向量或位列表(仅包含 01 位值得列表)组成,初始值均为 0

 

        2. 添加占坑位:对 KEY 进行多次hash(KEY ) ——> 取模运行 一> 得到坑位

        3. 判断是否存在 :查询某个key是否存在时,先把这个 key 通过相同的多个 hash 函数进行运算,查看对应的位置是否都为 1,只要有一个位为零,那么说明布隆过滤器中这个 key 不存在;如果这几个位置全都是 1,那么说明极有可能存在;

 总结

  1. 有,是很可能有;无,是肯定无
  2. 使用时最好不要让实际元素数量远大于初始化数量,一次给够避免扩容
  3. 当实际元素数量超过初始化数量时,应对布隆过滤器进行重建;重新分配更大的过滤器,再将所有的历史元素批量add 进行 

使用场景

  •  解决缓存穿透问题,Redis结合bitmap使用
  • 黑名单校验,识别垃圾邮寄
  • 安全连接网址,全球网站判断
  • 等。。。

实现布隆过滤器

整体架构 

 二进制数组构建过程

  1. 预加载符合条件得记录
  2. 计算每条记录得hash
  3. 计算hash值对应得bitmap数组位置
  4. 修改值

 查询元素是否存在得过程

  1. 计算元素得hash值
  2. 计算hash值对应二进制数组得位置
  3. 找到数组中对应位置的值,0 代表不存在,1 代表存在 

 代码落地

 初始化白名单

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * 初始化布隆过滤器
 *
 * @author :liao.wei
 * @date :2023/9/23 16:13
 * @package : com.mco.utils.bloomfilter
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class BloomFilterInitUtil {
	
	public static final String WHITE_CACHE_KEY_CUSTOMER = "white_list_customer";
	
	private final RedisTemplate redisTemplate;
	
	/**
	 * 初始化工具
	 */
	@PostConstruct
	public void init() {
		// 白名单key 加载到过滤器
		String key = "customer:2";
		// 计算hash值,对计算结果取绝对值(因为存在负值)
		int hashVal=Math.abs(key.hashCode());
		//计算位数位置(通过hashVal和2的32次方取模后,余数)
		long index= (long) (hashVal%Math.pow(2,32));
		log.info(key+"-对应的位置-"+index);
		//设置redis 中bitmap 对应位置的坑位,设置 1
		redisTemplate.opsForValue().setBit(WHITE_CACHE_KEY_CUSTOMER,index,true);
	}
}

在Redis 中检查一下是否置为1 

检查工具

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 * 布隆过滤器检查工具
 *
 * @author :liao.wei
 * @date :2023/9/23 16:24
 * @package : com.mco.utils.bloomfilter
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class CheckUtil {
	private final RedisTemplate redisTemplate;
	
	public boolean checkWithBloomFilter(String checkItem, String key) {
		// 计算hash值,对计算结果取绝对值(因为存在负值)
		int hashVal = Math.abs(key.hashCode());
		//计算位数位置(通过hashVal和2的32次方取模后,余数)
		long index = (long) (hashVal % Math.pow(2, 32));
		log.info(key + "-对应的位置-" + index);
		//设置redis 中bitmap 对应位置的坑位,设置 1
		return redisTemplate.opsForValue().getBit(checkItem, index);
	}
}

应用布隆过滤

//-------------加入布隆过滤器---------------
		if (!checkUtil.checkWithBloomFilter(WHITE_CACHE_KEY_CUSTOMER, key)) {
			log.info("无此customer");
			return null;
		}
		log.info("进入");
		//---------------------------

优缺点

优点缺点
高效插入和查询,内存占用bit空间少不能删除,存在hash冲突,可能造成误删除
存在误差,不能精确过滤
🌹 以上分享 Redis 布隆过滤器实际应用,如有问题请指教。
 
🌹🌹 如你对技术也感兴趣,欢迎交流。
 
🌹🌹🌹  如有需要,请👍点赞💖收藏🐱‍🏍分享 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一介布衣+

做好事,当好人

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值