package com.zhao.sian.delta.config;
import java.util.Objects;
import com.google.common.hash.Funnel;
import com.google.common.hash.Hashing;
public class BloomFilter<T> {
private int numHashFunctions;
private int bitSize;
private Funnel<T> funnel;
public BloomFilter(Funnel<T> funnel, int expectedInsertions, double fpp) {
if (Objects.isNull(funnel)) {
throw new IllegalArgumentException("funnel cannot be empty");
}
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;
}
/**
* Calculate the length of the bit array
*/
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)));
}
/**
* Count the number of executions of the hash method
*/
private int optimalNumOfHashFunctions(long n, long m) {
return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));
}
}
package com.zhao.sian.delta.config;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class RedisService {
@Autowired
private RedisTemplate<String, ?> redisTemplate;
/**
* Add value to bloom filter
*/
public <T> void addByBloomFilter(BloomFilter<T> bloomFilter, String key, T value) {
if (Objects.isNull(bloomFilter)) {
throw new IllegalArgumentException("bloomFilterHelper cannot be empty");
}
int[] offset = bloomFilter.murmurHashOffset(value);
for (int i : offset) {
redisTemplate.opsForValue().setBit(key, i, true);
}
}
/**
* Determine whether the value exists in the bloom filter
*/
public <T> boolean existByBloomFilter(BloomFilter<T> bloomFilter, String key, T value) {
if (Objects.isNull(bloomFilter)) {
throw new IllegalArgumentException("bloomFilter cannot be empty");
}
int[] offset = bloomFilter.murmurHashOffset(value);
for (int i : offset) {
if (!redisTemplate.opsForValue().getBit(key, i)) {
return false;
}
}
return true;
}
}
private BloomFilter<String> bloomFilter= new BloomFilter<>((Funnel<String>) (from, into) -> into.putString(from, Charsets.UTF_8)
.putString(from, Charsets.UTF_8), 10000 , 0.01);