前言
最近在研究布隆過濾器(如果不瞭解什麼是布隆過濾器的,推薦看如何判斷一個元素在億級數據中是否存在?),發現Guava提供了封裝好的類,但是隻能單機使用,一般現在的應用都是部署在分佈式系統的,所以想找個可以在分佈式系統下使用的布隆過濾器,找了半天只找到一個基於redis開發的模塊項目ReBloom,但是這個是需要額外安裝的,而且文檔裏只說了怎麼在docker下運行,沒研究過docker所以放棄了。後來找到一篇博客講怎麼利用布隆過濾器統計消息未讀數的(博客地址不記得了,是一位淘寶同學寫的),博客最後放了一份整合redis和bloomFilter的代碼demo,詳見BloomFilter.java,看了下實現比較簡單,但是使用方式不是我想要的,所以參考着自己整理了一份。
廢話少說,先上代碼
BloomFilterHelper
package com.doodl6.springmvc.service.cache.redis;
import com.google.common.base.Preconditions;
import com.google.common.hash.Funnel;
import com.google.common.hash.Hashing;
public class BloomFilterHelper<T> {
private int numHashFunctions;
private int bitSize;
private Funnel<T> funnel;
public BloomFilterHelper(Funnel<T> funnel, int expectedInsertions, double fpp) {
Preconditions.checkArgument(funnel != null, "funnel不能爲空");
this.funnel = funnel;
bitSize = optimalNumOfBits(expectedInsertions, fpp);
numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, bitSize);
}
int[] murmurHashOffset(T value) {
int[] offset = new int[numHashFunctions];
long hash64 = Hashing.murmur3_128().hashObject(value, funnel).asLong();
int hash1 = (int) hash64;
int hash2 = (int) (hash64 >>> 32);
for (int i = 1; i <= numHashFunctions; i++) {
int nextHash = hash1 + i * hash2;
if (nextHash < 0) {
nextHash = ~nextHash;
}
offset[i - 1] = nextHash % bitSize;
}
return offset;
}
/**
* 計算bit數組長度
*/
private int optimalNumOfBits(long n, double p) {
if (p == 0) {
p = Double.MIN_VALUE;
}
return (int) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
}
/**
* 計算hash方法執行次數
*/
private int optimalNumOfHashFunctions(long n, long m) {
return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));
}
}