目录
然后就是判断布隆过滤器bitSet数组中是否含有对应的key
实现思路
(39条消息) Redis布隆过滤器_Fairy要carry的博客-CSDN博客
首先最重要的自定义hash()
1.首先判断key是否为null,否则返回0——>2.然后数组长度-1-i(目的使散列均匀,因为我们定义一个数组,全是辅助多次hash,所以需要-i保留特点),然后就是(size-1-i)&((h=key.hashcode())^h>>>16)——>3.非常关键在这里,计算key的hash值后,然后^key的hash>>>16,目的是保留key的特点,保证散列均匀,因为size-1-i(像hashMap默认size为16,那么15对应的二进制为1111,那么就只能与hash的低位四个进行运算,那么保留特点就很少),所以>>>16保留了key hash低位16的特点,然后再^key.hashCode()->保证了高位16的特点(这样就保证了key的特点)
private int hash(Object key, int i) {
int h;
//BloomFilter_Size-i归根结底是为了保证散列均匀,保证每一次hash后key的特点——>之前push也是对key进行多次hash
int index = key == null ? 0 : (BloomFilter_Size - 1 - i) & ((h = key.hashCode()) ^ (h >>> 16));
return index > 0 ? index : -index;
}
然后就是将key放入bitSet
思路:1.计算key的hash(利用辅助hash数组对key进行多次hash),得到位置index后放入数组
/**
* 2.存放key
* 思路:1.遍历布隆过滤器的hash数组,对key进行多次hash并且保存在BitSet数组中
*
* @param key
*/
public void push(Object key) {
Arrays.stream(HelperBloom).forEach(i -> bitSet.set(hash(key, i)));
currentBaseBean++;
}
然后就是判断布隆过滤器bitSet数组中是否含有对应的key
思路:1.一样的,这里巧妙的是利用了&&,因为我们对key进行了多次hash,所以我们遍历辅助hash数组进行多次hash,根据对应index位置从bitSet取出看是否能取出,若为false,那么后面全为false——>2.直接利用&&,result默认为true,&&有一个为false那么结果就是false
/**
* 3.计算key的hash值并且去bitSet寻找看是否有位置,如果有返回true
* 思路:利用&&,从bitSet取出对应key的hash的index,如果没有返回false,因为&&所以结果false
*
* @param key
* @return
*/
public boolean isContain(Object key) {
boolean result=true;
for (int i : HelperBloom) {
result = result && bitSet.get(hash(key, i));
}
return result;
}
代码
import java.util.Arrays;
import java.util.BitSet;
/**
* @author diao 2022/9/7
*/
public class BloomFilter {
//后面hash函数会用到,用来生成不同的hash值,可以随便给,但别给奇数
private final int[] ints = {6, 8, 16, 38, 58, 68};
private Integer currentBeanCount = 0;
//你的布隆过滤器容量
private int DEFAULT_SIZE = Integer.MAX_VALUE;
//bit数组,用来存放结果
private final BitSet bitSet = new BitSet(DEFAULT_SIZE);
public BloomFilter() {
}
public BloomFilter(int size) {
if (size <= (2 << 8)) {
throw new RuntimeException("size is too small");
}
DEFAULT_SIZE = size;
}
//获取当前过滤器的对象数量
public Integer getCurrentBeanCount() {
return currentBeanCount;
}
//计算出key的hash值,并将对应下标置为true
public void push(Object key) {
for (int i : ints) {
bitSet.set(hash(key, i));
}
currentBeanCount++;
}
//判断key是否存在,true不一定说明key存在,但是false一定说明不存在
public boolean contain(Object key) {
boolean result = true;
for (int i : ints) {
result = result && bitSet.get(hash(key, i));
}
return result;
}
//hash算法,借鉴了hashmap的算法
private int hash(Object key, int i) {
int h;
int index = key == null ? 0 : (DEFAULT_SIZE - 1 - i) & ((h = key.hashCode()) ^ (h >>> 16));
return index > 0 ? index : -index;
}
public static void main(String[] args) {
BloomFilter bf = new BloomFilter ();
bf.push("张学友");
bf.push("郭德纲");
bf.push("特雷杨");
bf.push(666);
System.out.println(bf.contain("张学友"));//true
System.out.println(bf.contain("张学友 "));//false
System.out.println(bf.contain("张学友1"));//false
System.out.println(bf.contain("郭德纲"));//true
System.out.println(bf.contain("老鹰特雷杨8"));//false
System.out.println(bf.contain(666));//true
System.out.println(bf.contain(888));//false
}
}