方式一 (自定义)
在这里插入代码片
package com.cao.customerview.bloom;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.BitSet;
/**
* description: 自定义布隆过滤器来解决 缓存穿透问题
*/
public class MyBoomFilter {
//预期存储的数据量
private int n ;
//误判率
private double p ;
// m
private int m ;
//hash函数个数
private int k ;
//
private BitSet bitMap ;
/**
* 构造器
* @param n 存储过程目标数据量
* @param p 误判率
* */
public MyBoomFilter(int n , double p){
this.n = n ;
this.p = p ;
}
/**
* 添加元素
* */
public void addElement(String element){
if (bitMap == null){
//init
init();
}
int[] posArr = getIndexs(element);
for (int posTmp : posArr){
bitMap.set(posTmp , true);
}
}
/**
* 初始化
* */
public synchronized void init(){
if(this.m == 0){
this.m = (int)((-n * Math.log(this.p)) / (Math.log(2) * Math.log(2)));
}
if(this.k == 0){
this.k = (int) Math.max(1, Math.round(this.m / this.n * Math.log(2)));
}
if (bitMap == null){
bitMap = new BitSet(this.m) ;
}
System.out.println("this.m >> "+m);
System.out.println("this.n >> "+n);
}
/**
* 获取K个函数计算elment值的下标数组
* @param element
* */
private int[] getIndexs(String element){
int[] retArr = new int[this.k] ;
for (int i=0 ;i<this.k;i++){
retArr[i] = MD5Hash(element+i) % this.m ;
}
return retArr ;
}
/**
* 判断是否存在
* @param element
* */
private boolean isExist(String element){
int[] retArr = getIndexs(element) ;
boolean flag = true ;
for (int tmpPos : retArr){
flag = flag && bitMap.get(tmpPos) ;
}
return flag;
}
/**
* 测试自定义布隆过滤器
* */
private static void testMyBoomFilter(){
MyBoomFilter myBoomFilter = new MyBoomFilter(1000000, 0.0003) ;
for (int i=0 ;i < 1000000; i++){
myBoomFilter.addElement("abc"+i);
}
int count = 0 ;
for (int i=0; i < 2000000; i++){
if(myBoomFilter.isExist("abc"+i)){
count ++ ;
}
}
System.out.println("count: "+count);
}
private int MD5Hash(String key){
MessageDigest md5 = null ;
try{
md5 = MessageDigest.getInstance("md5");
byte[] keyBytes = key.getBytes() ;
md5.update(keyBytes);
BigInteger bi = new BigInteger(md5.digest());
return Math.abs(bi.intValue());
}catch(Exception e){
e.printStackTrace();
}
return -1;
}
public static void main(String[] args){
testMyBoomFilter();
}
}
方式二(guava提供的布隆过滤器方案)
(1)引入jar包
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>com.baqend</groupId>
<artifactId>bloom-filter</artifactId>
<version>1.0.7</version>
</dependency>
(2)代码片
package com.cao.customerview.bloom;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import java.nio.charset.Charset;
/**
* description: guava提供的布隆过滤器方案
*/
public class MyGuavaFilter {
public static void main(String[] args){
//存储数据量
int storeNum = 1000000 ;
BloomFilter bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")),
storeNum, 0.0003); //fpp 误判率
for (int i=0 ; i < storeNum; i++){
bloomFilter.put("abc"+i);
}
int count=0 ;
for (int i=0 ; i < 2000000; i++){
if (bloomFilter.mightContain("abc"+i)){
count ++ ;
}
}
System.out.println("count:"+ count);
}
}