ブルームフィルターとは何ですか?見てみましょう!

 ブルームフィルター、名前を見てください、それは単なるフィルターではありません!まず第一に、フィルターは、ふるい、ガーゼ、および大きな粒子をろ過するために使用される他のツールなど、すべての人に知られています。フィルタを使用すると、不要なものを除外して、最終的に必要なものを取得できます。特定のミネラルウォーターの広告を覚えておいてください。すべてのプロセスは20以上のフィルタリングプロセスを通過します!牛革が爆発した!たぶん、砂や何かをろ過することは、ろ過の層と見なすことができます!【微笑み:はは】

数日前、Redisを見ていたときに、BitMapという構造を見つけました。それを読み終えた後、私は叫びました。いいやつ、これはブルームフィルターのルートではありません。それで、私は静かに私の心の中で矢印を打ち、ブルームフィルターを指さしました。

さあ、最初にBaiduエントリを追加し、単語数を表示します。

ブルームフィルター(ブルームフィルター)は、1970年にブルームによって提案されました。これは実際には非常に長いバイナリベクトルと一連のランダムマッピング関数です。ブルームフィルターを使用して、要素がコレクションに含まれているかどうか取得できますその利点は、スペース効率とクエリ時間が一般的なアルゴリズムよりもはるかに優れていることですが、欠点は、特定の誤認識率と削除の難しさがあることです。

この種のエントリーの説明は、一部の仲間にはあまり明確ではないかもしれないので、平易な言葉で話しましょう。

ブルームフィルターは、簡単に言えば、フィルタリングに使用されますが、どのようにフィルタリングしますか?まず、0から1億などの多数のセグメントを準備します。次に、各数値に対応するtrueとfalseの値があり、デフォルトはfalseです。次に、Idなどのパラメータを使用してここでリクエストを受け取りました。どうすればフィルタリングできますか?まず、最初にデータベース内のすべてのIDを数回ハッシュし(3回実行しましょう)、次に3つのハッシュ値があり、次にこれら3つの数値の対応する数値フィールドの値をtrueに変更します。 300,000のデータがある場合、ハッシュを900,000回要求してから、これらのハッシュの対応する数値フィールドの値をtrueに変更します。もちろん、重複する可能性があります。(これは事前に行われています。少なくとも、リクエストが到着する前に行われています。)

リクエストが来た後、リクエストされたパラメータのハッシュを3回要求し、この数値フィールドから対応する値を確認しました。trueの場合は合格、falseの場合は合格です。申し訳ありませんが、IDは明らかにデータベースにありません。愛はどこにありますか。主は待っていません。

もちろん、特定のデータセグメントでハッシュが繰り返されると、データも存在する可能性があります。非常に幸運です。データベースにはありませんが、ハッシュの値は3回真であり、フィルターからも。

そのため、ブルームフィルターは、既存のものは確実に通過し、存在しないものは通過する可能性があるという特徴があります。

この時点ではバーを持ち上げないでください。フィルターは主に負荷と攻撃を阻止するためのものです。魚が不足している場合でも、コードが処理された後は、サーバーまたはDBへの損傷はほとんどありません。この少量のデータ処理は許容されます。

簡単な図を見てみましょう。

ブルームフィルターの概略図

図に示すように、次のデータセグメントを事前に準備し、データを事前にハッシュして、データセグメントのtrueとfalseを変更します。リクエストが来ると、ハッシュに従ってデータをフィルタリングするかどうかが判断されます。

さて、モデル図が出てきましたが、どのように実装しますか?

配列を作成することですか?ねえ!それはまさに起こります、このデータセグメントは単なる配列ではありませんか?次に、データにtrueとfalseを書き込んで、関数が実現されないようにしますか?

はい、機能は実現されており、回路図から、このデータセグメントは非常に大きくなければならないことが理解できます。そうでない場合、何気なく埋められてしまいます。それでは、フィルタリングには他に何が必要ですか?言い過ぎではなく、数千万人!数千万のレベルの配列またはリストを作成してもよろしいですか?これで攻撃を適切にフィルタリングできるかどうかについては話さないでください。サーバーには、この数千万のレベルの配列だけで十分です。さあ、ちょっと計算してみましょう。Javaでオブジェクトを作成するには、最小の計算である16バイトに1,000万を掛けたもの、つまり1億6,000万バイト、つまり約1GBを実行しましょう。

次に、この1GBアレイに対して複数のクエリと判断を実行してから、フィルタリングする必要があります。

サーバーへの負荷を軽減できるかどうかについては話さないでください。そのようなブルー​​ムフィルターが他にもある場合は、おめでとうございます。ゲームオーバー!サーバーが直接ダウンしているので、どのようなフィルターが必要です!

サーバーを強制終了するだけです。必要なフィルターは何ですか。 !
サーバーを強制終了するだけです。必要なフィルターは何ですか。

       ブルームフィルター:「配列は絶対に使用できません。この人生で配列を殺す必要はありません!私たちは規律あるフィルターでもあります!」

        配列は必要ないので、何を使うべきですか?Baiduのエントリも言っています-非常に長いバイナリベクトル。

バイナリに関しては、コンピュータの底面の一部が含まれているので、ここで少し説明します。

コンピュータプログラミングは、最終的にはJava、C、C ++などの高級言語からアセンブリ言語、そして機械語に変換され、最終的には0と1の2つの数値に変換されます。コンピュータはこれら2つの数値のみを認識します。もしも..else ..?愛はどこにあるのか!

初期の大型コンピューターは実際にはパンチホール認識ですが、何世代にもわたる更新の後、現在のコンピューターは、ストレージであろうとコンピューティング能力であろうと、祖先をどれだけ上回っているかをもはや知りません。

さて、話が多すぎます。

誰もがストレージに精通していますよね?最下層がわからなくても、いつも頻繁に接触します。たとえば、特定のハードドライブにある数百ギガバイトのアクション映画、数十MBのデータを使用する携帯電話など、これらは実際には2つの数値1と0の送信です。

おなじみの単位は一般的にTB(1024GB)、GB(1024MB)、MB(1024KB)、KB(1024B)、B(バイト)ですが、Bは最小の単位ですか?

番号!このB(バイト)はまだ1と0から少し離れています。つまり、ビット、1バイト= 8ビットです。ビットは凡例に1と0が格納される場所であり、1ビットは1または0が格納される場所です。 。したがって、1Byteが8ビットを占め、1KBが1024 * 8 = 8192ビット、1MBが8,388,608ビットであることは明らかです。各ビットが数値を表す場合、8,388,608(百万レベル)を表すことができ、1と0で表されます。正誤問題ですが、1MBで800万を超えるデータセグメントを表すことができるということではないでしょうか。また、特定の数値を直接見つけて、0と1を直接返すことができ、速度は直接O(1)です。これはブルームフィルターだけではありませんか?それどころか、ブルームフィルターはこのストレージメカニズムを利用するだけではいけませんか?概略図を見てみましょう。

ブルームフィルターストレージの概略図

ほら、ブルームフィルターを完成させるのに約10〜20Mのスペースしか必要ありませんが、香りがしませんか?どんな配列が欲しい!ブルームフィルターは非常にわかりやすいですが、単独で実装すると少し面倒ですが、気にしないでください!Javaがパッケージ化されているので、まずは見てみましょう。

public class BloomTest {

    // 需要存储的数据,数据段的话是后台创建的,是根据下面的概率来的, 不用你管的,
    private static int dataAmount = 500000;

    // 百分比,就是漏网之鱼的概率,布隆过滤器总有一些不存在的数据能通过,
    //这个就是不存在的数据能通过的概率
    // 千分之一的概率
    private static double rate = 0.001;
    
    public static void main(String[] args) {

        // 本来想用Integer的,但是字段哪可能刚好是数字啊,字符串的可能更大,适应性更强,反正也是求hash,差别不大。
        BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), dataAmount, 0.001);


        // 先塞数据吧
        for (int i = 0; i < dataAmount; i++) {
            String uuid = UUID.randomUUID().toString();
            bloomFilter.put(uuid);
        }
        //数据放好了,开始拦截呗,放50000数据过来呗,
        int number = 0;
        for (int i = 0; i < 50000; i++) {
            String uuid = UUID.randomUUID().toString();
            if (bloomFilter.mightContain(uuid)){
                number++;
            }
        }
        System.out.println("50000条数据误判的数据量为:"+number
                +"\n所占百分百:"+ new BigDecimal(number).divide(new BigDecimal(50000)));
    }
}

このメインメソッドは自分で実行できます。パーセンテージは0.001に近く、多かれ少なかれ、以下は私の実行の1つの結果です。

50000条数据误判的数据量为:51
所占百分百:0.00102

Process finished with exit code 0

  ちなみに、コードをコピーするときは、GoogleのBloomFilterのMaven依存関係(バージョンはユーザーによって異なります)を追加することを忘れないでください。

       <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
        </dependency>

どうですか?このブルームフィルターはとても使いやすいですか?とても簡単ですか?本当にエキサイティングですか?ねえ、でも多くの人には使われていません。

これは単一サーバー用のブルームフィルターです。サービスを展開していますが、それでもスタンドアロンですか?私をからかってるの!分散環境では、マシンごとにブルームフィルターがあり、メモリにお金はかかりませんか?あなたは暴君ですか?それではお願いします。

Redis:「分散環境?私はそれに精通しています、来て、来て、私を来させてください、へへ!」

だから、Redisがステージにいます!一部のバディはRedisにブルームフィルターを単独で実装しますが、Java統合Redisにはカプセル化があります。簡単にするために、Beanインジェクションを作成しませんでしたが、すでに簡単なテストメソッドを作成し、作成メソッドに合格しました。次に、ブルームフィルターを直接使用します。

public class RedissonBloomTest {

    // 需要存储的数据,数据段的话是后台创建的,是根据下面的概率来的, 不用你管的,
    private static int dataAmount = 1000000;

    // 百分比,就是漏网之鱼的概率,布隆过滤器总有一些不存在的数据能通过,
    //这个就是不存在的数据能通过的概率
    // 千分之一的概率
    private static double rate = 0.001;

    // 客户端服务,spring中,应该是创建bean,然后直接注入的,我这边为了简单把Redisson在构造方法中初始化了
    RedissonClient redisson;

    public static void main(String[] args) {
        //获取redissonClient 服务
        RedissonClient redissonClient = new RedissonBloomTest().getRedisson();
        //获取(创建)布隆过滤器
        RBloomFilter<String> redisBloomFilter = redissonClient.getBloomFilter("RedisBloomFilter");
        //初始化布隆过滤器
        redisBloomFilter.tryInit(dataAmount, rate);
        // 代码copy过来

        // 先塞数据吧
        for (int i = 0; i < dataAmount; i++) {
            String uuid = UUID.randomUUID().toString();
            //这里塞数据就很慢了,建议少放点数据,生产中肯定要提前弄好,不然很容易出事故哦
            redisBloomFilter.add(uuid);
        }
        //数据放好了,开始拦截呗,放100000数据过来呗,
        int number = 0;
        for (int i = 0; i < 100000; i++) {
            String uuid = UUID.randomUUID().toString();
            if (redisBloomFilter.contains(uuid)){
                number++;
            }
        }
        System.out.println("100000条数据误判的数据量为:"+number
                +"\n所占百分百:"+ new BigDecimal(number).divide(new BigDecimal(100000)));

        redissonClient.shutdown();
    }

    static Config config = new Config();

    static {
        config.useSingleServer()
                .setAddress("redis://127.0.0.1:6379");
    }

    public RedissonBloomTest(){
        redisson = Redisson.create(config);
    }

    public static Config getConfig() {
        return config;
    }

    public RedissonClient getRedisson() {
        return redisson;
    }
}

これは私が実行した後の結果です:

100000条数据误判的数据量为:1847
所占百分百:0.01847

この結果は、設定したエラー率とは少し違うようです。ブルームフィルターのサイズを見て、Googleの100万のデータと比較しました。ブルームフィルターのサイズはほぼ同じで、すべて数十です。数百万の。ただし、このfalseProbabilityは少し異なるようです。(誰かがそれを見たら、遠慮なくアドバイスしてください!)

この問題は少し解決する必要があるかもしれません。ブルームフィルターの長所と短所を見てみましょう。

優れた:シンプル、便利、大量のデータのフィルタリングが簡単

不備:データは事前​​に並べ替えて追加する必要があり、一度しか使用できません。基本データを削除または追加すると、ブルームフィルターがリセットされるため、非常に不便です。

ブルームフィルターの適用シナリオもあります。

1.インタビューでよく聞かれるキャッシュの浸透、ブルームフィルターを使用して直接フィルターで除外する

2.ビッグデータの重複排除。たとえば、クローラーシステムでは、URLの重複排除を行う必要があります。

3.ブルームフィルターは、スパムフィルタリング機能でも一般的に使用されます。このフィルターのため、通常の電子メールの一部は通常スパムディレクトリに配置されます。これは誤判断が原因であり、確率は非常に低いです。

 

それは危険で危険です、そして私は月末にこれを出力するだけです。

犠牲も勝利もありません〜

あなたが書いたものがまずまずだと感じたら、親指を立ててください〜

おすすめ

転載: blog.csdn.net/zsah2011/article/details/115300961