1.计算出key的哈希值。
根据hash值和固定段大小取模计算出偏移位offset。根据固定前置+hash值/固定段大小计算出所处段的bitKey。根据bitKey和offset判断是否存在。如果存在然后调用containsFromDb判断是否存在。将redis setbit进行分段可以避免单个key数据量过大。如果redis是集群也可以将分出来的段根据jedis crc16算法有概率的被打算在各个节点上,避免单个节点过热。代码示例:package six.com.crawler.work.space;
import java.util.Objects;
import redis.clients.jedis.Jedis;
public class RedisAndDbBloomFilter {
private String nameSpace; private Jedis jedis; private int fixSize; public RedisAndDbBloomFilter(String nameSpace,Jedis jedis,int fixSize){ this.nameSpace=nameSpace; this.jedis=jedis; this.fixSize=fixSize; } private int getHash(String key){ return key.hashCode(); } private void addToDb(int hash,String key){ //TODO 将记录保存至db } private boolean containsFromDb(int hash,String key){ //TODO 根据 hash key 查询数据库是否存在 return false; } /** * 根据hash和fixSize 算出bitKey * @param hash * @return */ private String getBitKey(int hash){ int bitKeyIndex=hash/fixSize; String bitKey=nameSpace+bitKeyIndex; return bitKey; } /** * 判断给定的key是否存在 * @param key * @return */ public boolean contains(String key){ //TODO 如果是集群模式这里需要分布式锁,如果是单机这里需要线程锁 Objects.requireNonNull(key, "the key must not be null"); int hash=getHash(key); int offset=hash%fixSize; String bitKey=getBitKey(hash); Boolean result=jedis.getbit(bitKey,offset); if(result.booleanValue()&&containsFromDb(hash, key)){ return true; } return false; } /** * 根据给定的key添加一个过滤记录 * @param key */ public void addRecord(String key){ //TODO 如果是集群模式这里需要分布式锁,如果是单机这里需要线程锁 int hash=getHash(key); int offset=hash%fixSize; String bitKey=getBitKey(hash); jedis.setbit(bitKey,offset, true); addToDb(hash, key); }}