Java はブルーム フィルターを実装します

ブルームフィルターとは

ブルーム フィルターは、1970 年にブルームによって提案されました。実際には、非常に長いバイナリ配列 + 要素がセット内に存在するかどうかを判断する一連のハッシュ アルゴリズム マッピング関数で構成されます。
ブルーム フィルターを使用して、要素がセット内にあるかどうかを取得できます。その利点は、スペース効率とクエリ時間が一般的なアルゴリズムよりもはるかに優れていることですが、欠点は、一定の誤認識率と削除の難しさです。

個人の公開アカウントに注意を払うことを歓迎します [技術を楽しく学ぶ] 交流と勉強

シーン

10億の携帯電話番号があるとしたら、特定の携帯電話番号がリストにあるかどうかを判断しますか?

mysqlできますか?

通常、データ量がそれほど多くない場合は、mysql ストレージの使用を検討できます。すべてのデータをデータベースに保存し、ライブラリが存在するかどうかを毎回確認するためにライブラリに移動します。ただし、データ量が数千万を超えると、mysql のクエリ効率は非常に低くなり、多くのパフォーマンスが消費されます。

ハッシュセット可能

データを HashSet に入れ、HashSet の自然な重複排除を使用できます. クエリは contains メソッドを呼び出すだけで済みますが、ハッシュセットはメモリに格納されます. データ量が大きすぎる場合、メモリは直接迫った。

ブルームフィルターの特徴

  • 挿入とクエリは効率的で、使用するスペースは少なくなりますが、返される結果は不確定です。
  • 要素が存在すると判断された場合、必ずしも存在するとは限りません。しかし、要素が存在しないと判断された場合、それは存在してはなりません。
  • ブルーム フィルターは要素を追加できますが、要素を削除してはなりません。これにより、誤検知率が増加します。

ブルームフィルターの原理

ブルーム フィルターは、実際には BIT 配列であり、一連のハッシュ アルゴリズムを介して対応するハッシュをマップし、ハッシュに対応する配列の添え字の位置を 1 に変更します。クエリを実行すると、データに対して一連のハッシュ アルゴリズムが実行されて添え字が取得され、データが BIT 配列から取得されます.1 の場合は、データが存在する可能性があることを意味します.0 の場合は、存在しなければならないことを意味します.存在しない。

なぜエラー率があるのですか

ブルーム フィルターが実際にデータをハッシュすることはわかっているため、どのアルゴリズムを使用しても、2 つの異なるデータによって生成されたハッシュがまったく同じである可能性があります。これは、よくハッシュ競合と呼ばれるものです。

最初にデータを挿入する: 技術をよく学ぶ

image.png

データの挿入:

image.png

这是如果查询一条数据,假设他的hash下标已经标为1了,那么布隆过滤器就会认为他存在

image.png

常见使用场景

缓存穿透

java实现布隆过滤器

package com.fandf.test.redis;

import java.util.BitSet;

/**
 * java布隆过滤器
 *
 * @author fandongfeng
 */
public class MyBloomFilter {

    /**
     * 位数组大小
     */
    private static final int DEFAULT_SIZE = 2 << 24;

    /**
     * 通过这个数组创建多个Hash函数
     */
    private static final int[] SEEDS = new int[]{4, 8, 16, 32, 64, 128, 256};

    /**
     * 初始化位数组,数组中的元素只能是 0 或者 1
     */
    private final BitSet bits = new BitSet(DEFAULT_SIZE);

    /**
     * Hash函数数组
     */
    private final MyHash[] myHashes = new MyHash[SEEDS.length];

    /**
     * 初始化多个包含 Hash 函数的类数组,每个类中的 Hash 函数都不一样
     */
    public MyBloomFilter() {
        // 初始化多个不同的 Hash 函数
        for (int i = 0; i < SEEDS.length; i++) {
            myHashes[i] = new MyHash(DEFAULT_SIZE, SEEDS[i]);
        }
    }

    /**
     * 添加元素到位数组
     */
    public void add(Object value) {
        for (MyHash myHash : myHashes) {
            bits.set(myHash.hash(value), true);
        }
    }

    /**
     * 判断指定元素是否存在于位数组
     */
    public boolean contains(Object value) {
        boolean result = true;
        for (MyHash myHash : myHashes) {
            result = result && bits.get(myHash.hash(value));
        }
        return result;
    }

    /**
     * 自定义 Hash 函数
     */
    private class MyHash {
        private int cap;
        private int seed;

        MyHash(int cap, int seed) {
            this.cap = cap;
            this.seed = seed;
        }

        /**
         * 计算 Hash 值
         */
        int hash(Object obj) {
            return (obj == null) ? 0 : Math.abs(seed * (cap - 1) & (obj.hashCode() ^ (obj.hashCode() >>> 16)));
        }
    }

    public static void main(String[] args) {
        String str = "好好学技术";
        MyBloomFilter myBloomFilter = new MyBloomFilter();
        System.out.println("str是否存在:" + myBloomFilter.contains(str));
        myBloomFilter.add(str);
        System.out.println("str是否存在:" + myBloomFilter.contains(str));
    }


}
复制代码

Guava实现布隆过滤器

引入依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version>
</dependency>
复制代码
package com.fandf.test.redis;

import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

/**
 * @author fandongfeng
 */
public class GuavaBloomFilter {

    public static void main(String[] args) {
        BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),100000,0.01);
        bloomFilter.put("好好学技术");
        System.out.println(bloomFilter.mightContain("不好好学技术"));
        System.out.println(bloomFilter.mightContain("好好学技术"));
    }
}
复制代码

hutool实现布隆过滤器

引入依赖

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.3</version>
</dependency>
复制代码
package com.fandf.test.redis;

import cn.hutool.bloomfilter.BitMapBloomFilter;
import cn.hutool.bloomfilter.BloomFilterUtil;

/**
 * @author fandongfeng
 */
public class HutoolBloomFilter {
    public static void main(String[] args) {
        BitMapBloomFilter bloomFilter = BloomFilterUtil.createBitMap(1000);
        bloomFilter.add("好好学技术");
        System.out.println(bloomFilter.contains("不好好学技术"));
        System.out.println(bloomFilter.contains("好好学技术"));
    }

}
复制代码

Redisson实现布隆过滤器

引入依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.20.0</version>
</dependency>
复制代码
package com.fandf.test.redis;
 
import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
 
/**
 * Redisson 实现布隆过滤器
 * @author fandongfeng
 */
public class RedissonBloomFilter {
 
    public static void main(String[] args) {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        //构造Redisson
        RedissonClient redisson = Redisson.create(config);
 
        RBloomFilter<String> bloomFilter = redisson.getBloomFilter("name");
        //初始化布隆过滤器:预计元素为100000000L,误差率为1%
        bloomFilter.tryInit(100000000L,0.01);
        bloomFilter.add("好好学技术");
 
        System.out.println(bloomFilter.contains("不好好学技术"));
        System.out.println(bloomFilter.contains("好好学技术"));
    }
}
复制代码

Supongo que te gusta

Origin juejin.im/post/7215454015713919031
Recomendado
Clasificación