要素がセットに含まれているかどうかをすばやく判断するにはどうすればよいですか?このトピックは私が最近のインタビューでよく尋ねる質問であり、さまざまな人々がこの質問に対して多くの異なる答えを持っています。
今日は、ブルームフィルターの助けを借りて、ほとんどの人が言及しないソリューションを紹介したいと思います。
1.ブルームフィルターとは何ですか?
ブルームフィルターは、1970年にブルームという名前の兄弟によって提案されました。
実際、これは、バイナリベクトル(またはビット配列)と一連のランダムマッピング関数(ハッシュ関数)で構成されるデータ構造と見なすことができます。
その利点は、スペース効率とクエリ時間が一般的なアルゴリズムよりもはるかに優れていることです。欠点は、特定の誤認識率があり、削除が難しいことです。
2.実装の原則
写真を思い付く
ブルームフィルターアルゴリズムの主なアイデアは、ハッシュにn個のハッシュ関数を使用して、さまざまなハッシュ値を取得し、ハッシュに従って配列のさまざまなインデックス位置にマップすることです(この配列の長さは非常に長い場合があります)。次に、対応するインデックスビットの値を1に設定します。
要素がセットに含まれるかどうかを判断するには、k個の異なるハッシュ関数を使用してハッシュ値を計算し、ハッシュ値の対応するインデックス位置より上の値が1であるかどうかを確認します。1でないものがある場合これは、要素がコレクションに存在しないことを意味します。
ただし、要素がセットに含まれていると判断することもできますが、要素は含まれていません。この要素のインデックス位置の1は、他の要素によって設定されているため、誤判定の可能性があります(これが、上記はセットに存在する可能性があります)特定のハッシュの競合があるため、根本的な原因)。
注:誤検出率が低いほど、対応するパフォーマンスは低くなります。
3.機能
ブルームフィルターは、要素がセット内にあるかどうかを判断するために使用できます。他のデータ構造と比較すると、ブルームフィルターには空間と時間の面で大きな利点があります。
上記の一言に注意してください:おそらく。ここにサスペンスが残っていますが、これについては以下で詳しく分析します。
-
指定されたデータが存在するかどうかを確認します
-
キャッシュの侵入(要求されたデータがキャッシュ要求データベースを直接バイパスすることを回避するために有効かどうかを判断する)など、メールボックスのスパムフィルタリング、ブラックリスト機能などを防止します。
4.具体的な実現
ブルームフィルターのアルゴリズムのアイデアを読んだ後、特定の実装の説明を開始します。
最初に例を挙げましょう。WangcaiとXiaoqiangの2つの文字列があるとします。これらは、それぞれ3回ハッシュアルゴリズムを実行し、対応する配列のインデックス位置の値(配列の長さが16であると仮定)を1に設定します。ハッシュ結果によると、最初に「繁栄の富」というフレーズを見てください。
Wangjingが3回ハッシュした後、値はそれぞれ2、4、および6になります。次に、インデックス値はそれぞれ2、4、および6として取得できるため、インデックスの値は(2、4 、6)の配列は1に設定されます。残りは0と見なされます。ここで、豊かな富を検索する必要があるとします。同じ3回のハッシュの後、インデックス2に対応する位置の値が見つかります。 、4、6はすべて1であるため、豊かな富が存在する可能性があると判断できます。
次に、Xiaoqiangをブルームフィルターに挿入します。取得した添え字が1、3、5であると仮定すると、実際のプロセスは上記と同じです。
Wangcaiの存在を除けば、Xiaoqiangはこの時点のブルームフィルターでは次のようになり、WangcaiとXiaoqiangを組み合わせた実際の配列は次のようになります。
これで、データの一部があります:9527。ここで、9527が存在するかどうかを判断する必要があります。3回のハッシュ後に9527によって取得された添え字が、5、6、および7であるとします。下付き文字7の位置の値が0であることが判明した場合、9527が存在してはならないことを確実に判断できます。
次に、 国内の007が登場しました。3回のハッシュの後、取得された下付き文字は2、3、および5です。下付き文字2、3、および5に対応する値はすべて1であることが判明したため、大まかに判断できます。国内の007が存在する可能性がある こと。ただ、実は今のデモンストレーションの後、国内の007は全く存在していません。2、3、5のインデックス位置の値が1である理由は、他のデータが設定されているためです。
そういえば、ブルームフィルターの役割をみんなが理解しているかどうかはわかりません。
5.コードの実装
Javaプログラマーとして、私たちは本当に満足しています。私たちは多くのフレームワークとツールを使用しており、それらは基本的にカプセル化されています。ブルームフィルターには、Googleでカプセル化されたツールクラスを使用します。もちろん、探索できる方法は他にもあります。
最初に依存関係を追加します
<!--布隆过滤依赖-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>25.1-jre</version>
</dependency>
コードの実装
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import java.nio.charset.Charset;
public class BloomFilterDemo {
public static void main(String[] args) {
/**
* 创建一个插入对象为一亿,误报率为0.01%的布隆过滤器
* 不存在一定不存在
* 存在不一定存在
* ----------------
* Funnel 对象:预估的元素个数,误判率
* mightContain :方法判断元素是否存在
*/
BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")), 100000000, 0.0001);
bloomFilter.put("死");
bloomFilter.put("磕");
bloomFilter.put("Redis");
System.out.println(bloomFilter.mightContain("Redis"));
System.out.println(bloomFilter.mightContain("Java"));
}
}
コメントには具体的な説明が書かれています。この時点で、誰もがブルームフィルターとその使用方法を理解している必要があると思います。
6.実際の戦闘
キャッシュの浸透がブルームフィルターによって解決されるシナリオをシミュレートしてみましょう。
まず、キャッシュの浸透とは何か知っていますか?
キャッシュの浸透とは、ユーザーがキャッシュにもデータベースにも存在しないデータにアクセスすることを意味します。キャッシュが存在しないため、同時実行性が高い場合、ユーザーはデータベースにアクセスします。データベースを圧倒するのは簡単です
ブルームフィルターはこの問題をどのように解決しますか?彼
原則は次のとおりです。データベース内のすべてのクエリ条件をブルームフィルターに入れます。クエリ要求が来ると、最初にブルームフィルターでチェックされ、要求されたクエリ値が存在すると判断された場合は、次のように処理されます。チェック;要求されたクエリが存在しないと判断された場合、直接破棄されます。
そのコードは次のとおりです。
String get(String key) {
String value = redis.get(key);
if (value == null) {
if(!bloomfilter.mightContain(key)){
return null;
}else{
value = db.get(key);
redis.set(key, value);
}
}
return value;
}
7.まとめ
この記事では、ブルームフィルターとは何ですか?効果は何ですか?実装原理とブルームフィルターは、コードレベルの多くの側面から説明されています。私はあなたの学習の進歩に貢献できることを願っています。