Tencent Two Sides: QQ 番号は 40 億あり、メモリは 1G に制限されています。重複排除するにはどうすればよいですか? その質問には唖然としました!

40 億 QQ 番号、1G メモリに制限されている場合、重複排除する方法は?

40 億の unsigned int をメモリに直接保存する場合は、次のものが必要です。

4*4000000000 /1024/1024/1024 = 14.9G, いくつかの単語の繰り返しがあることを考慮すると、基本的に 1G の容量では十分ではありません。

この機能を実現するには、ビットマップを使用できます。

ビットマップを使用する場合、数値は 1 ビットのみを占有する必要があるため、40 億の数値は次のようになります。

4000000000 * 1 /8 /1024/1024 = 476M

以前の14.9Gと比較して、スペースを大幅に節約できます。

たとえば、QQ 番号「907607222」をビットマップに配置したい場合は、907607222 の位置を見つけて、それを 1 に設定する必要があります。

このようにして、ビットマップに 40 億個の数値を入力すると、すべての位置が 1 であることを示し、1 でない位置は存在しないことを示します。同じ QQ 番号を 1 に設定するのは 1 回だけです。 are 1 という数値をたどることができます。

ビットマップとは何ですか? 用途は何ですか?

ビットマップ (BitMap) の基本的な考え方は、ビットを使用して要素をマークすることです。ビットとは、コンピューターの最小単位、つまりコンピューターでよく 0 と 1 と呼ばれるものです。これはビットで表されます。

いわゆるビットマップは実際にはビット配列です。つまり、各位置がビットであり、その値は 0 または 1 になります。

上のビットマップと同様に、1、4、6 を表すために使用できます。

ビットマップを使用しない場合、1、4、6 の 3 つの整数を記録したい場合は、3 つの unsigned int を使用する必要があります。各 unsigned int は 4 バイトを占めることが知られているため、バイトです。 a 3*4 = 12word セクションは 8 ビットなので12*8 = 96ビット。

したがって、ビットマップの最大の利点はスペースを節約できることです。

ビットマップには、特に重複排除や並べ替えなどのシナリオで多くの用途があり、有名なブルーム フィルターはビットマップに基づいて実装されています。

ただし、ビットマップには特定の制限もあります。つまり、ビットマップは 0 と 1 のみを表現でき、他の数値は格納できません。だから彼は、真か偽かを表現できるこの種のシーンにのみ適しています。

オープンソースで無料の Spring Boot 実践プロジェクトを推奨します。

https://github.com/javastacks/spring-boot-best-practice

ブルームフィルターとは何ですか?またその実装原理は何ですか?

ブルーム フィルターは、要素がセット (ビット配列) に存在する可能性があるかどうかを迅速に取得するために使用されるデータ構造です。

その基本原理は、複数のハッシュ関数を使用して要素を複数のビットにマップし、これらのビットを 1 に設定することです。要素をクエリするとき、これらのビットがすべて 1 に設定されている場合、その要素はコレクション内に存在する可能性が高いと見なされます。そうでない場合は、要素は絶対に存在しません。

したがって、ブルーム フィルターは、要素が存在してはならないかどうかを正確に判断できますが、ハッシュ衝突が存在するため、要素が存在しなければならないと判断できません。存在する可能性があると判断するしかない。

そのため、存在しないHero要素がhash1、hash2、hash3を通過する際に、他の値のハッシュ結果と衝突してしまうというブルームフィルタの誤判定が発生する可能性があります。そうなると、存在していると誤って判断されてしまいますが、実際には存在しません。

この誤判定の確率を減らすためには、ハッシュ衝突の確率を減らし、より多くのハッシュアルゴリズムを導入することが主な方法です。

ブルームフィルターの動作プロセスは次のとおりです。

1. ブルームフィルターを初期化する

ブルーム フィルターを初期化するときは、セットのサイズと誤検知率を指定する必要があります。ブルーム フィルターにはビット配列と複数のハッシュ関数が含まれており、各ハッシュ関数はインデックス値を生成します。

2. ブルームフィルターに要素を追加する

ブルーム フィルターに要素を追加するには、まず要素を複数のハッシュ関数に渡して複数のインデックス値を生成し、次にこれらのインデックス値に対応するビットを 1 に設定する必要があります。これらのインデックス値がすでに 1 に設定されている場合、再度設定する必要はありません。

3. クエリ要素がブルームフィルターに存在するかどうか

ブルーム フィルターに要素が存在するかどうかをクエリするには、要素を複数のハッシュ関数に渡して複数のインデックス値を生成し、これらのインデックス値に対応するビットがすべて 1 に設定されているかどうかを判断する必要があります。これらのビットがすべて 1 に設定されている場合、その要素はセット内に存在する可能性が高いと見なされますが、それ以外の場合は絶対に存在しません。

ブルーム フィルターの主な利点は、要素が特定のセットに属しているかどうかを迅速に判断でき、空間的および時間的に高い効率を達成できることです。ただし、次のような欠点もあります。

  1. ブルームフィルターは要素の有無を判定する際に一定の誤判定率を伴います。
  2. ブルーム フィルターでは、要素を削除するには対応するビットを 0 に設定する必要があるため、要素の削除がより困難になりますが、これらのビットは他の要素と共有される可能性があります。

アプリケーションシナリオ

ブルーム フィルターは効率が高いため広く使用されており、一般的なシナリオは次のとおりです。

1. Web クローラー:クローラー プログラムは、ブルーム フィルターを使用して、すでにクロールされている Web ページをフィルターで除外し、クロールの繰り返しとリソースの無駄を避けることができます。

2. キャッシュ システム:キャッシュ システムは、ブルーム フィルターを使用してクエリがキャッシュに存在するかどうかを判断できるため、クエリ キャッシュの数が減り、クエリの効率が向上します。ブルーム フィルターは、キャッシュの侵入の問題を解決するためにもよく使用されます。

3. 分散システム:分散システムでは、ブルーム フィルターを使用して要素が分散キャッシュに存在するかどうかを判断し、すべてのノードでのクエリを回避し、ネットワーク負荷を軽減できます。

4. スパム フィルタリング:ブルーム フィルタを使用して、電子メール アドレスがスパム リストに含まれているかどうかを判断し、スパムをフィルタリングできます。

5. ブラックリスト フィルタリング:ブルーム フィルタを使用して、IP アドレスまたは携帯電話番号がブラックリストに含まれているかどうかを判断し、悪意のあるリクエストを防止できます。

使い方

ブルーム フィルターは、Java のサードパーティ ライブラリを使用して実装できます。一般的なライブラリには、Google Guava ライブラリ、Apache Commons ライブラリ、Redis などがあります。

グアバなど:

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
public class BloomFilterExample {
    public static void main(String[] args) {
        // 创建布隆过滤器,预计插入100个元素,误判率为0.01
        BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(), 100, 0.01);
        // 插入元素
        bloomFilter.put("Lynn");
        bloomFilter.put("666");
        bloomFilter.put("八股文");
        // 判断元素是否存在
        System.out.println(bloomFilter.mightContain("Lynn")); // true
        System.out.println(bloomFilter.mightContain("张三"));  // false
    }
}

Apache コモンズ:

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.collections4.BloomFilter;
import org.apache.commons.collections4.functors.HashFunctionIdentity;
public class BloomFilterExample {
    public static void main(String[] args) {
        // 创建布隆过滤器,预计插入100个元素,误判率为0.01
        BloomFilter<String> bloomFilter = new BloomFilter<>(HashFunctionIdentity.hashFunction(StringUtils::hashCode), 100, 0.01);
        // 插入元素
        bloomFilter.put("Lynn");
        bloomFilter.put("666");
        bloomFilter.put("八股文");
        // 判断元素是否存在
        System.out.println(bloomFilter.mightContain("Lynn")); // true
        System.out.println(bloomFilter.mightContain("张三"));  // false
    }
}

Redis は Bloom モジュールを通じて使用でき、Redisson は次の目的で使用できます。

Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
RBloomFilter<String> bloomFilter = redisson.getBloomFilter("myfilter");
bloomFilter.tryInit(100, 0.01);
bloomFilter.add("Lynn");
bloomFilter.add("666");
bloomFilter.add("八股文");
System.out.println(bloomFilter.contains("Lynn"));
System.out.println(bloomFilter.contains("张三"));
redisson.shutdown();

まず RedissonClient オブジェクトを作成し、次にこのオブジェクトを通じて RBloomFilter オブジェクトを取得し、tryInit メソッドを使用してブルーム フィルターを初期化し、追加できる要素の最大数を 100 として指定し、誤検知率は 0.01 です。

次に、add メソッドを使用して要素「狗小HA」、「666」、および「八边文」をブルーム フィルターに追加し、contains メソッドを使用して要素がブルーム フィルターに存在するかどうかを確認します。

または、ジェダイは次のこともできます。

Jedis jedis = new Jedis("localhost");
jedis.bfCreate("myfilter", 100, 0.01);
jedis.bfAdd("myfilter", "Lynn");
jedis.bfAdd("myfilter", "666");
jedis.bfAdd("myfilter", "八股文");
System.out.println(jedis.bfExists("myfilter", "Lynn"));
System.out.println(jedis.bfExists("myfilter", "张三"));
jedis.close();

著作権に関する声明: この記事は CSDN ブロガー「code.song」のオリジナル記事であり、CC 4.0 BY-SA 著作権契約に従って、転載する場合は元のソース リンクとこの声明を添付してください。元のリンク: https://blog.csdn.net/songmulin/article/details/130814507

最近のおすすめ記事:

1. 1,000 を超える Java 面接の質問と回答 (2022 年最新バージョン)

2.素晴らしい!Java コルーチンが登場します。

3. Spring Boot 2.x チュートリアル、包括的すぎる!

4.画面を爆発や爆発で埋め尽くさないで、デコレーターモードを試してください。これがエレガントな方法です。

5.最新リリースの「Java 開発マニュアル (松山編)」をすぐにダウンロードしてください!

気分がいいので、「いいね!」+「転送」を忘れないでください!

おすすめ

転載: blog.csdn.net/youanyyou/article/details/130954898