目录
什么是布隆过滤器?
作用:
实现一个简单的布隆过滤器:
解析:
什么是布隆过滤器?
布隆过滤器(Bloom Filter)是一种用于快速检查一个元素是否可能存在于一个集合中的数据结构,它通过使用位数组和哈希函数来实现。虽然它可以告诉你一个元素“可能存在”或“肯定不存在”,但它无法告诉你一个元素“肯定存在”。
他的原理就是通过多个哈希函数,将一个元素映射到位数组的多个位置上,将0置为1。在判断一个元素是否存在时,就会用多个相同哈希函数映射,然后判断映射的位置上是否都为1,若都为1说明可能存在,因为可能有其他的一些元素映射会将这些位置正好都置为了1,所以可能会发生很小概率的误判,当然如果不都为1,那么一定是不存在的。
这就是为什么说它可以告诉你一个元素“可能存在”或“肯定不存在”,但它无法告诉你一个元素“肯定存在”。 图片来源于网络。
作用:
布隆过滤器通常用于在大型数据集中快速确定某个元素是否存在。
-
缓存优化: 布隆过滤器可以用于缓存系统中,以快速判断一个请求的数据是否存在于缓存中。通过在布隆过滤器中存储缓存中已有的键,可以在缓存查找之前迅速排除掉那些肯定不在缓存中的键,减少实际的缓存查询次数。
-
数据去重: 布隆过滤器可以用于数据去重,即判断一个数据是否已经存在于某个数据集中。在某些场景下,需要处理大量重复数据时,可以先使用布隆过滤器进行预判,如果布隆过滤器认为数据已存在,则无需进行实际的去重操作。
-
拦截垃圾邮件和恶意网址: 布隆过滤器可以用于拦截垃圾邮件、恶意网址等不良信息。在垃圾邮件过滤器或恶意网址过滤器中,可以将已知的垃圾邮件或恶意网址加入布隆过滤器,以快速过滤掉一部分恶意信息,减轻后续处理的负担。
-
网络爬虫 URL 去重: 在网络爬虫系统中,布隆过滤器可以用于去重 URL,避免重复抓取同一网页。通过在布隆过滤器中存储已经抓取过的 URL,可以快速判断一个 URL 是否已经被抓取过。
-
恶意的请求:黑客构造一些合理的但是在数据库中不存在的大量请求,由于数据合理前端可能过滤不掉,同时每个请求还不同,用redis也难以去重,大量请求直接查询数据库,造成数据库的巨大压力,这时就可以用布隆过滤器,快速判断请求数据是否在数据库中,若存在,才会去向下再去查redis和数据库。
实现一个简单的布隆过滤器:
public class Main{
public static void main(String[] args) {
BuLong.add("abc");
BuLong.add("def");
System.out.println(BuLong.check("abc")); // true
System.out.println(BuLong.check("123")); // false
}
}
class BuLong {
private static int size = 100010;
private static int hashFunction = 3; // 哈希函数的个数
private static BitSet flags = new BitSet(size); // true为1,false为0
/**
* 检测一个字符串是否在redis或数据库种
*/
public static boolean check(String s) {
for (int i = 0; i < hashFunction; i++) { // 假设有三个哈希函数
int idx = (s + i).hashCode() % size;
if (!flags.get(idx)) return false;
}
return true;
}
/**
* 添加字符串
*/
public static void add(String s) {
for (int i = 0; i < hashFunction; i++) {
int idx = (s + i).hashCode() % size;
flags.set(idx, true);
}
}
}
解析:
因为只用01表示,所以为数组直接用bitSet来表示,真为1,假为0。
private static BitSet flags = new BitSet(size); // true为1,false为0
其实就是进行了一个简单模拟,这里多个哈希函数直接用的这样:
for (int i = 0; i < hashFunction; i++) { // 假设有三个哈希函数
int idx = (s + i).hashCode() % size;
if (!flags.get(idx)) return false;
}
传入的字符串 + 第 i 个 哈希函数,然后对size取余,就表示当前哈希函数映射的位置,我们置为1,也就是true。
添加和检测都是利用哈希,改变或者检测对应的位置是否都为1而已。