布隆过滤器

2021-06-09  本文已影响0人  幻如常

布隆过滤器

特点

  1. 判断key不存在,就是百分百不存在

  2. 判断key存在,则有一定的误判几率,如果hash的越分散,位数组容量越大,那么误判概率越小

原理

  1. 首先有一个位数组(该数组中只能存放0和1),位数组中每个元素的初始值都为0

  2. 然后准备多个hash函数,目的是增加分散度,避免碰撞概率过大

  3. 每一个hash函数都对key进行hash算法得到其在位数组中的位置,如果我设定了6个哈希函数,那么我就要进行6次hash计算,得到6个位数组中的位置,在对应位数组中的位置,把元素值设为1

  4. 如何判断一个值是否在布隆过滤器(也就是位数组中呢)中,那么就对该值进行存储时一样的hash算法,得到对应的6个位数组中位置,然后取出对应位置的元素,判断该元素是否为1,如果有一个不为1,那么该值肯定不在布隆过滤器中,如果都为1,那么可能在布隆过滤器中(不能保证百分百存在),因为不同字符串hash出来的位置可能是相同的,这种情况就可以适当调整位数组的大小或者调整我们的hash哈数来减少碰撞的概率

java方式实现

import java.util.BitSet; 
public class MyBloomFilter {
 //位数组的容量
 private static final int DEFAULT_SIZE = 2 << 24;
 /*** 通过这个数组可以创建 6 个不同的哈希函数 */ 
 private static final int[] SEEDS = new int[]{3, 13, 46, 71, 91, 134};    /*** 位数组。数组中的元素只能是 0 或者 1 */ 
 private BitSet bits = new BitSet(DEFAULT_SIZE); 
 /*** 存放包含 hash 函数的类的数组,即该数组中放的都是hash哈数 */
 private SimpleHash[] func = new SimpleHash[SEEDS.length]; 
 /*** 初始化多个包含 hash 函数的类的数组,每个类中的 hash 函数都不一样 */ public MyBloomFilter() { 
 // 初始化多个不同的 Hash 函数 
 for (int i = 0; i < SEEDS.length; i++) { 
 func[i] = new SimpleHash(DEFAULT_SIZE, SEEDS[i]); 
 } 
 }
 /*** 添加元素到位数组 */ 
 public void add(Object value) { 
 for (SimpleHash f : func) {
 bits.set(f.hash(value), true); 
   } 
 }
 /*** 判断指定元素是否存在于位数组 */ 
 public boolean contains(Object value) {
 boolean ret = true; 
 for (SimpleHash f : func) { 
 ret = ret && bits.get(f.hash(value)); 
 }
 return ret; 
 }
 /*** 静态内部类。用于 hash 操作! */ 
 public static class SimpleHash { 
 private int cap; 
 private int seed; 
 public SimpleHash(int cap, int seed) {
 this.cap = cap;
 this.seed = seed; 
 }
 /*** 计算 hash 值 */ 
 public int hash(Object value) { 
 int h; 
 return (value == null) ? 0 : Math.abs(seed * (cap - 1) & ((h = value.hashCode()) ^ (h >>> 16))); 
    } 
   } 
}

谷歌开源Guava的布隆过滤器(缺陷就是只能单机使用,且容量扩展不容易)

  1. 导入依赖

     <groupId>com.google.guava</groupId> 
     <artifactId>guava</artifactId> 
     <version>28.0-jre</version> 
    </dependency></pre>
    
  2. 实现(创建一个最多存放 1500个整数的布隆过滤器,并且我们可以容忍误判的概率为百分之0.01)

    // 创建布隆过滤器对象 
    BloomFilter<Integer> filter = BloomFilter.create( Funnels.integerFunnel(), 1500, 0.01); 
    // 判断指定元素是否存在 
    System.out.println(filter.mightContain(1)); System.out.println(filter.mightContain(2)); 
    // 将元素添加进布隆过滤器 
    filter.put(1); filter.put(2);
    System.out.println(filter.mightContain(1)); 
    System.out.println(filter.mightContain(2));

Redis中的布隆过滤器

解决redis缓存穿透问题:Redis缓存雪崩和缓存穿透解决方案-布隆过滤器(总结)_java_liuyuan的博客-CSDN博客

上一篇 下一篇

猜你喜欢

热点阅读