5分でブルームフィルタを理解する。10億レベルのデータフィルタリングアルゴリズムは、知っておく価値があります。

5分でブルームフィルタを理解する。10億レベルのデータフィルタリングアルゴリズムは、知っておく価値があります。

[[339720]]

この記事はWeChatの公開アカウント「Uncle Who Knows a Little Code」から転載したもので、著者はUncle Who Knows a Little Codeです。この記事を転載する場合は、Uncle Who Knows Codeの公式アカウントまでご連絡ください。

Bloom フィルターについて正式に説明する前に、次のビジネス シナリオを見てみましょう。

Redis は、ソフトウェア アーキテクチャでよく使用されるコンポーネントです。最も一般的な使用方法は、データベースへの負荷を軽減するために、ホット データを Redis にキャッシュすることです。クエリ プロセス中に最も一般的な使用方法は、Redis をクエリすることです。データが見つかった場合は、直接返されます。Redis に存在しない場合は、データベースのクエリを続行します。

この方法により、データベース アクセスの回数を減らすことができますが、「データがキャッシュにないときにデータベースをクエリする」ことは、同時実行性の高い環境では依然としてリスクを伴います。たとえば、要求されたデータの 90% がキャッシュにない場合、これらの要求はすべてデータベースに送られ、キャッシュ侵入が発生します。

では、この問題を解決する方法はあるのでしょうか? これは、「特定のデータが確実に存在しない」ことを判断できるブルーム フィルターを使用することで解決できます。

01. ブルームフィルタの概念

ブルーム フィルタは、「ブルーム」という人物によって提案されました。それ自体は非常に長いバイナリ ベクトル (配列として想像してください) と一連のランダム マッピング関数 (複数のハッシュ関数として想像してください) です。バイナリ ベクトルには 0 または 1 が格納されます (ブルーム フィルタについて学習する前に、まず BitMap アルゴリズムを理解すると理解しやすくなります)。

例えば、顧客の携帯電話番号を条件として顧客情報を照会したい場合、通常は携帯電話番号をキャッシュのキーとして設定します。長さ 16 の Bloom フィルターを設定してみましょう。

ブルームフィルタは 0 に初期化されます。

13800000000 に対して hash1()、hash2()、hash3() 演算を実行し、5、9、12 の 3 つの結果を取得します。対応する位置を 1 に設定します。

18900000000 に対して hash1()、hash2()、hash3() 演算を実行し、2、8、12 の 3 つの結果を取得します。対応する位置を 1 に設定します。これで、2、5、8、9、12 はすべて 1 になり、残りの要素は 0 になります。

電話番号が存在するかどうかを確認したい場合はどうすればいいでしょうか?

13700000000 に対してそれぞれ hash1()、hash2()、hash3() 演算を実行し、1、9、13 の 3 つの結果を取得します。次に、1 番目、9 番目、13 番目のビットの値が 0 か 1 かを判定します。すべて 1 でない場合は、13700000000 がこの Bloom フィルター上にないことを意味し、これにより、「特定のデータが確実に存在しない」ことが確認されます。

もちろん、ブルーム フィルタには問題があることもわかります。つまり、データが存在することを保証できないということです。たとえば、18000000000 に対して hash1()、hash2()、hash3() 演算を実行すると、結果は 5、8、9 となり、たまたま 1 になります。しかし、実際にはこのデータは存在しないため、ブルーム フィルタには一定の誤判定率があります。

また、計算後に複数のデータが同一の位置にマッピングされる可能性があるため(138と189の計算結果はともに12)、ビットごとにカウンターを追加しない限り、ブルームフィルターを削除することは困難です。削除する場合は、カウンターが0になるまでカウンターから1を減算し、ブルームフィルターの対応する位置を0に変更する必要があります。

02. 機能概要

ある要素が確実に存在しないと判断することは可能ですが、ある要素が確実に存在すると判断することは不可能です。

バイナリベクトルが長いほど、マッピング関数の数が多くなり、誤判定率が低くなります。誤判定率が事前に判定できれば、ブルームフィルタの長さも推測できます。

要素は追加できますが、削除することはできません (カウンターが増加しない限り)。

挿入クエリのストレージスペースと時間の複雑さの点で大きな利点があります。

この記事の冒頭のビジネス シナリオに戻ると、キャッシュ侵入を防ぐために、ブルーム フィルターを使用して、確実に存在しないデータをフィルター処理できます。誤って判断されたリクエストはデータベースに配置されますが、侵入の数は大幅に削減されます。

03. ブルームフィルタを手書きする

コードを書くことが目的ではなく、コーディングのプロセスは理解を深めることです。

まず、ビットマップを定義する必要があります。JDK には、対応するデータ構造クラス java.util.BitSet が既に存在します。

  1. //ブルームフィルターを設定する
  2. プライベートint DEFAULT_SIZE = 1 << 30;
  3.  
  4. プライベート BitSet ビットセット;

マッピング関数のセットも必要です。ここでは、加法ハッシュ関数を使用して、6 つの異なるハッシュ関数に対応する 6 つの素数を設定できます。

  1. //長さ6の素数配列を定義し、ランダムマッピング用の6つのハッシュ関数を生成できる
  2. プライベートint []シード = {3, 7, 13, 31, 37, 61};
  3.  
  4. プライベートHashFunction[] functions = new HashFunction[seeds.length];

コンストラクターで初期化し、BitSet の長さを設定し、マッピング関数を生成します。

  1. /**
  2. * 初期化
  3. */
  4. パブリックブルームフィルタ() {
  5. ビットセット = 新しい BitSet(DEFAULT_SIZE);
  6.  
  7. ( int i = 0; i < seeds.length; i++) {
  8. functions[i] = 新しいHashFunction(DEFAULT_SIZE、seeds[i]);
  9. }
  10. }

要素を追加するときは、入力パラメータに対して 6 つのハッシュ操作を実行し、結果に対応する位置を 1 に変更します (BitSet に対応する位置は true に変更されます)。

  1. /**
  2. * 要素を追加し、ハッシュ演算の結果を取得し、対応する位置を1( true に変更します。
  3. * @パラメータ値
  4. */
  5. パブリックvoid add (文字列値) {
  6. 値 != null の場合{
  7. (HashFunction f: 関数)の場合{
  8. bitset.set (f.hash(値), true );
  9. }
  10. }
  11. }

Bloom マネージャーに要素が存在するかどうかを判断するには、入力パラメータに対して 6 つのハッシュ演算を実行し、結果の対応する位置が 0 か 1 (真か偽か) かどうかを確認する必要があります。ビットの 1 つが 0 の場合、データが確実に存在しないことを意味します。すべてが 1 の場合、データが存在する可能性がある (高い確率で存在する) ことを意味します。

  1. /**
  2. * 要素がブルームフィルタ内にあるかどうかを判定する
  3. * @パラメータ値
  4. * @戻る 
  5. */
  6. パブリックブール値には(文字列値)が含まれます{
  7. 値 == null場合
  8. 戻る 間違い;
  9. }
  10.  
  11. (HashFunction f: 関数)の場合{
  12. if(!bitset.get(f.hash(値))){
  13. //位置が1( true )でない場合は存在しないことを意味し、直接falseを返します 
  14. 戻る 間違い;
  15. }
  16. }
  17.  
  18. 戻る 真実;
  19. }

04. Guava の BloomFilter

Bloom マネージャーの実装に役立つオープンソース フレームワークはすでに多数存在します。たとえば、すぐに使用できる Bloom フィルターを備えた Google 製の Guava ツール ライブラリなどです。

  1. パブリッククラスBloomFilterTest {
  2. 公共 静的void main(String[] args){
  3. 整数 サイズ= 1000000;
  4. //ブルームフィルター
  5. BloomFilter< Integer > bloomFilter = BloomFilter.create ( Funnels.integerFunnel(),サイズ, 0.001);
  6.      
  7. ( int i = 0; i <サイズ; i++) {
  8. ブルームフィルタを put(i);
  9. }
  10.      
  11. リスト<整数> リスト = 新しい ArrayList<整数>(1000);
  12. ( int i =サイズ+ 1; i <サイズ+ 10000; i++) {
  13. if (bloomFilter.mightContain(i)) {
  14. リストに追加します(i);
  15. }
  16. }
  17. System.out.println ( "誤判定数:" +list.size ( ));
  18. }
  19. }

<<:  2020年グローバルスマート教育会議でAI教育統合イノベーションの成果が発表されました

>>:  IDC: 人工知能への世界的支出は4年で倍増すると予想

ブログ    
ブログ    
ブログ    

推薦する

写真から3Dモデルを生成、GANとオートエンコーダが衝突して奇跡を起こす

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

報告書では、人工知能の新世代について再び言及しており、3つのキーワードが完全に解釈されている。

最近、「両会」の政府活動報告では、人工知能が再び言及された。「新世代人工知能の研究開発と応用を強化し...

...

ジャック・マーとイーロン・マスクは「愛し合い、憎み合っている」:人間とテクノロジーの競争の勝者は誰か?

8月29日、国家発展改革委員会、科学技術部、工業情報化部、中国サイバースペース管理局、中国科学院、...

SafetyNet: 自動運転における機械学習戦略のための安全な計画アプローチ

[[427712]] 2021年9月28日にarXivにアップロードされた論文「SafetyNet:...

ブロックチェーン技術を活用してディープフェイク動画の脅威に対抗する方法

デジタル革新が主流の時代において、ディープフェイク動画の増加は広く懸念されるようになっている。ディー...

メタバースの開発にはどのような重要な技術が必要ですか?

メタバースは、信頼できる資産価値とアイデンティティ認証を備えた仮想アクティビティを実行するためのプラ...

...

Toutiaoのアルゴリズムロジックを使用してMacOSを再設計しました

仕事以外では、私はほとんどの時間を2つの状態で過ごしています。1つは見出しを閲覧している状態で、もう...

AIアルゴリズムエンジニアの涙の体験談

[[425033]]私たちはしばらくの間、展開モデルの最適化に取り組んできました。ここ数日でようやく...

AI 主導のビジネス変革を通じてデジタル成熟を達成するにはどうすればよいでしょうか?

[[388979]]デジタル時代においては、情報の流れがあらゆるものの中心となります。すべてが感知...

ディープラーニング、NLP、コンピュータービジョン向けのトップ 30 Python ライブラリ

[[358174]] Gregory Piatetsky による次のグラフでは、各リポジトリにカテゴ...

グラフニューラルネットワーク (GNN) とは何ですか?

[51CTO.com クイック翻訳]グラフィックは人々の仕事や生活のいたるところに存在します。たと...

PaddlePaddle ディープラーニング実践 - 英語-フランス語翻訳マシン

自然言語処理[1]は、コンピュータサイエンスと人工知能の分野におけるもう一つの重要な方向性です。重要...

目から涙が溢れてきました!ビクーニャのデジタルツインは10年前の自分を再現し、10年間の対話は数え切れないほどの人々に影響を与えた

Reddit のネットユーザーが何か新しいことをやっている。彼は、自身のオンラインフットプリントデー...