偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

場(chǎng)景題:假設(shè)有40億QQ號(hào),但只有1G內(nèi)存,如何實(shí)現(xiàn)判重?

數(shù)據(jù)庫(kù) MySQL
使用 MySQL 數(shù)據(jù)庫(kù)判重,或使用 List.contains() 或 Set.contains() 判重就不行了,因?yàn)閿?shù)據(jù)量太大會(huì)導(dǎo)致內(nèi)存放不下,或查詢速度太慢等問(wèn)題。

當(dāng)數(shù)據(jù)量比較大時(shí),使用常規(guī)的方式來(lái)判重就不行了。例如,使用 MySQL 數(shù)據(jù)庫(kù)判重,或使用 List.contains() 或 Set.contains() 判重就不行了,因?yàn)閿?shù)據(jù)量太大會(huì)導(dǎo)致內(nèi)存放不下,或查詢速度太慢等問(wèn)題。

1.空間占用量預(yù)測(cè)

正常情況下,如果將 40 億 QQ 號(hào)存儲(chǔ)在 Java 中的 int 類型的話,一個(gè) int 占 4 字節(jié)(byte)那么 40 億占用空間大小為:

4000000000*4/1024/1024/1024=14.9 GB

1GB=1024MB,1MB=1024KB,1KB=1024B(byte)

所以,我們無(wú)法使用正常的手段進(jìn)行 40 億 QQ 號(hào)的存儲(chǔ)和去重判斷,那怎么實(shí)現(xiàn)呢?

2.解決方案

此問(wèn)題的常見(jiàn)解決方案有兩種:

  • 使用位數(shù)組 BitMap 實(shí)現(xiàn)判重。
  • 使用布隆過(guò)濾器實(shí)現(xiàn)判重。

具體來(lái)說(shuō)。

(1)位數(shù)組實(shí)現(xiàn)判重

位數(shù)組是指使用位(bit)組成的數(shù)組,每個(gè) QQ 號(hào)使用 1 位(bit)來(lái)存儲(chǔ),如下圖所示:

其中下標(biāo)用來(lái)標(biāo)識(shí)具體的數(shù)字,例如以上圖片標(biāo)識(shí) 1、3 數(shù)字存在,如果值為 0 表示不存在,這樣的話 40 億占用的位數(shù)組空間位 40 億 bit,也就是 4000000000/1024/1024/1024/8=0.465 GB,不到 1G 的內(nèi)存就可以存儲(chǔ) 40 億 QQ 號(hào)了,查詢某個(gè) QQ 號(hào)是否在線,只需要看這個(gè) QQ 下標(biāo)對(duì)應(yīng)的位置是否為 1,1 表示存在,0 表示不存在。

位數(shù)組代碼實(shí)現(xiàn)

位數(shù)組可以使用 Java 自帶的 BitSet 來(lái)實(shí)現(xiàn),它位于 java.util 包中,具體實(shí)現(xiàn)代碼如下:

import java.util.BitSet;

public class BitmapExample {
    public static void main(String[] args) {
        // 創(chuàng)建一個(gè)BitSet實(shí)例
        BitSet bitmap = new BitSet();

        // 設(shè)置第5個(gè)位置為1,表示第5個(gè)元素存在
        bitmap.set(5);

        // 檢查第5個(gè)位置是否已設(shè)置
        boolean exists = bitmap.get(5);
        System.out.println("Element exists: " + exists);  // 輸出: Element exists: true

        // 設(shè)置從索引10到20的所有位置為1
        bitmap.set(10, 21);  // 參數(shù)是包含起始點(diǎn)和不包含終點(diǎn)的區(qū)間

        // 計(jì)算bitset中所有值為1的位的數(shù)量,相當(dāng)于計(jì)算設(shè)置了的元素個(gè)數(shù)
        int count = bitmap.cardinality();
        System.out.println("Number of set bits: " + count);

        // 清除第5個(gè)位置
        bitmap.clear(5);

        // 判斷位圖是否為空
        boolean isEmpty = bitmap.isEmpty();
        System.out.println("Is the bitset empty? " + isEmpty);
    }
}

(2)布隆過(guò)器實(shí)現(xiàn)

布隆過(guò)濾器是基于位數(shù)組實(shí)現(xiàn)的,它是一種高效的數(shù)據(jù)結(jié)構(gòu),由布隆在 1970 年提出。它主要用于判斷一個(gè)元素可能是否存在于集合中,其核心特性包括高效的插入和查詢操作,但存在一定的假陽(yáng)性(False Positives)可能性。

布隆過(guò)濾器實(shí)現(xiàn)如下圖所示:

根據(jù) key 值計(jì)算出它的存儲(chǔ)位置,然后將此位置標(biāo)識(shí)全部標(biāo)識(shí)為 1(未存放數(shù)據(jù)的位置全部為 0),查詢時(shí)也是查詢對(duì)應(yīng)的位置是否全部為 1,如果全部為 1,則說(shuō)明數(shù)據(jù)是可能存在的,否則一定不存在。

布隆過(guò)器特性:如果布隆過(guò)濾器說(shuō)一個(gè)元素不在集合中,那么它一定不在這個(gè)集合中;但如果它說(shuō)一個(gè)元素在集合中,則有可能是不存在的(存在誤差,假陽(yáng)性)。

布隆過(guò)器代碼實(shí)現(xiàn)

布隆過(guò)濾器的常見(jiàn)實(shí)現(xiàn)有以下幾種方式:

使用 Google Guava BloomFilter 實(shí)現(xiàn)布隆過(guò)濾器,具體實(shí)現(xiàn)代碼如下:

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
public class BloomFilterExample {
    public static void main(String[] args) {
        // 創(chuàng)建一個(gè)布隆過(guò)濾器,設(shè)置期望插入的數(shù)據(jù)量為10000,期望的誤判率為0.01
        BloomFilter<String> bloomFilter = 
        BloomFilter.create(Funnels.unencodedCharsFunnel(), 10000, 0.01);
        // 向布隆過(guò)濾器中插入數(shù)據(jù)
        bloomFilter.put("data1");
        bloomFilter.put("data2");
        bloomFilter.put("data3");
        // 查詢?cè)厥欠翊嬖谟诓悸∵^(guò)濾器中
        System.out.println(bloomFilter.mightContain("data1")); // true
        System.out.println(bloomFilter.mightContain("data4")); // false
    }
}

使用 Hutool 框架 BitMapBloomFilter 實(shí)現(xiàn)布隆過(guò)濾器,如下代碼所示:

// 初始化
BitMapBloomFilter filter = new BitMapBloomFilter(10);
// 存放數(shù)據(jù)
filter.add("123");
filter.add("abc");
filter.add("ddd");
// 查找
filter.contains("abc");

使用 Redisson 框架中的 RBloomFilter 實(shí)現(xiàn)布隆過(guò)濾器,如下代碼所示:

Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 創(chuàng)建布隆過(guò)濾器,設(shè)置名稱和期望容量與誤報(bào)率
RBloomFilter<String> bloomFilter = 
redissonClient.getBloomFilter("myBloomFilter");
bloomFilter.tryInit(10000, 0.03); // 期望容量 10000,誤報(bào)率 3%
// 添加元素到布隆過(guò)濾器
String element1 = "element1";
bloomFilter.add(element1);
// 判斷元素是否存在
boolean mightExist = bloomFilter.contains(element1);
System.out.println("元素 " + element1 + " 可能存在: " + mightExist);
String element2 = "element2";
boolean mightExist2 = bloomFilter.contains(element2);
System.out.println("元素 " + element2 + " 可能存在: " + mightExist2);

其中 Google Guava BloomFilter 和 Hutool 框架 BitMapBloomFilter 為單機(jī)版的布隆過(guò)濾器實(shí)現(xiàn),不適用分布式環(huán)境。分布式環(huán)境要使用 Redisson 框架中的 RBloomFilter 來(lái)實(shí)現(xiàn)布隆過(guò)濾器,因?yàn)樗臄?shù)據(jù)是保存在 Redis 中間件的,而中間件天生支持分布式系統(tǒng)。

小結(jié)

位數(shù)組和布隆過(guò)濾器的區(qū)別如下:

  • 位數(shù)組:沒(méi)有誤判,但空間利用率低。
  • 布隆過(guò)濾器:空間利用率高,但存在對(duì)已經(jīng)存在的數(shù)據(jù)的誤判(不存在的數(shù)據(jù)沒(méi)有誤判)。

因此,如果對(duì)精準(zhǔn)度要求高可以使用位數(shù)組;如果對(duì)空間要求苛刻,可以考慮布隆過(guò)濾器。

責(zé)任編輯:姜華 來(lái)源: 磊哥和Java
相關(guān)推薦

2025-03-26 02:22:00

2024-03-11 16:01:29

BitMap數(shù)據(jù)去重開發(fā)

2025-05-26 01:40:00

2023-09-18 16:59:06

數(shù)據(jù)布隆過(guò)濾器

2024-06-03 06:45:18

2021-12-08 09:53:50

騰訊QQ號(hào)碼重復(fù)

2024-02-19 11:49:23

JavaBitMap類型

2024-03-06 09:22:23

C#數(shù)據(jù)庫(kù)判重

2016-12-21 15:33:11

中國(guó)移動(dòng)4G尚冰

2023-12-27 07:56:29

內(nèi)存哈希算法排序算法

2010-03-01 09:03:53

谷歌寬帶光纖

2025-01-14 16:14:10

2009-09-18 09:57:01

華碩服務(wù)器促銷

2021-04-21 18:57:16

二進(jìn)制存儲(chǔ)空間

2022-02-09 22:49:06

1G移動(dòng)通信

2019-03-28 06:31:01

2011-10-20 13:41:57

神舟臺(tái)式機(jī)

2019-03-10 15:54:22

5G通信4G

2012-05-21 18:13:42

360特供機(jī)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)