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

十億QQ號(hào)如何去重?你知道嗎?

開發(fā) 架構(gòu)
10億QQ號(hào)去重的本質(zhì),是將問題拆解到每個(gè)計(jì)算單元都能高效處理的粒度。今天這篇文章跟大家一起分享一些常見的解決方案,希望對(duì)你會(huì)有所幫助。

前言

最近在網(wǎng)上看到一個(gè)問題:10億QQ號(hào)如何去重?

我覺得挺有意思的。

今天這篇文章跟大家一起分享一些常見的解決方案,希望對(duì)你會(huì)有所幫助。

一、技術(shù)難點(diǎn)

1.數(shù)據(jù)規(guī)模分析

  • 原始數(shù)據(jù):10億×8字節(jié) = 8GB
  • HashSet去重:至少16GB內(nèi)存(Java對(duì)象開銷)
  • 理想方案:<1GB內(nèi)存

2. 核心挑戰(zhàn)

二、單機(jī)解決方案:位圖法

1.算法原理

利用位數(shù)組表示數(shù)字存在性:

public class BitMap {  
    privatefinalbyte[] bits;  
    
    public BitMap(int maxNum) {  
        this.bits = newbyte[(maxNum >> 3) + 1]; // 每byte存儲(chǔ)8個(gè)數(shù)字  
    }  
    
    public void add(int num) {  
        int arrayIndex = num >> 3;  // num/8  
        int position = num & 0x07;  // num%8  
        bits[arrayIndex] |= 1 << position;  
    }  
    
    public boolean contains(int num) {  
        int arrayIndex = num >> 3;  
        int position = num & 0x07;  
        return (bits[arrayIndex] & (1 << position)) != 0;  
    }  
}

2.QQ號(hào)范圍優(yōu)化

QQ號(hào)范圍:10000(5位) - 9999999999(10位)位圖內(nèi)存計(jì)算

(10^10 - 10^4) / 8 / 1024/1024 ≈ 1.16GB

優(yōu)化方案

// 偏移量?jī)?yōu)化:存儲(chǔ)(qq - 10000)  
public void add(long qq) {  
    long num = qq - 10000;  
    int arrayIndex = (int)(num >> 3);  
    int position = (int)(num & 7);  
    bits[arrayIndex] |= 1 << position;  
}

三、進(jìn)階方案:布隆過(guò)濾器

1.應(yīng)對(duì)內(nèi)存限制

2.參數(shù)設(shè)計(jì)與實(shí)現(xiàn)

public class BloomFilter {  
    privatefinal BitSet bitset;  
    privatefinalint size;  
    privatefinalint[] seeds;  
    
    public BloomFilter(int size, int hashCount) {  
        this.bitset = new BitSet(size);  
        this.size = size;  
        this.seeds = newint[hashCount];  
        for (int i = 0; i < hashCount; i++) {  
            seeds[i] = i * 31;  
        }  
    }  
    
    public void add(String qq) {  
        for (int seed : seeds) {  
            int hash = hash(qq, seed);  
            bitset.set(Math.abs(hash % size), true);  
        }  
    }  
    
    public boolean contains(String qq) {  
        for (int seed : seeds) {  
            int hash = hash(qq, seed);  
            if (!bitset.get(Math.abs(hash % size))) {  
                returnfalse;  
            }  
        }  
        returntrue;  
    }  
    
    private int hash(String value, int seed) {  
        // MurmurHash 實(shí)現(xiàn)  
        int result = 0;  
        for (char c : value.toCharArray()) {  
            result = seed * result + c;  
        }  
        return result;  
    }  
}

3.內(nèi)存優(yōu)化效果

方案

內(nèi)存消耗

誤差率

原始存儲(chǔ)

8 GB

0%

位圖法

1.16 GB

0%

布隆過(guò)濾器(0.1%)

171 MB

0.001

四、磁盤方案:外部排序與多路歸并

1.處理流程

2.關(guān)鍵代碼實(shí)現(xiàn)

// 外部排序  
public void externalSort(String input, String output) throws IOException {  
    List<File> chunks = splitAndSort(input, 100_000_000); // 每個(gè)文件1千萬(wàn)  
    mergeFiles(chunks, output);  
}  

// 多路歸并  
void mergeFiles(List<File> files, String output) {  
    PriorityQueue<MergeEntry> queue = new PriorityQueue<>();  
    List<BufferedReader> readers = new ArrayList<>();  

    // 初始化堆  
    for (File file : files) {  
        BufferedReader reader = new BufferedReader(new FileReader(file));  
        readers.add(reader);  
        String line = reader.readLine();  
        if (line != null) {  
            queue.add(new MergeEntry(line, reader));  
        }  
    }  

    try (BufferedWriter writer = new BufferedWriter(new FileWriter(output))) {  
        long last = -1;  
        while (!queue.isEmpty()) {  
            MergeEntry entry = queue.poll();  
            long qq = Long.parseLong(entry.value);  

            // 去重:只寫入不重復(fù)的QQ號(hào)  
            if (qq != last) {  
                writer.write(entry.value);  
                writer.newLine();  
                last = qq;  
            }  

            // 讀取下一行  
            String next = entry.reader.readLine();  
            if (next != null) {  
                queue.add(new MergeEntry(next, entry.reader));  
            }  
        }  
    } finally {  
        readers.forEach(r -> { try { r.close(); } catch (IOException e) {}});  
    }  
}  

class MergeEntry implements Comparable<MergeEntry> {  
    String value;  
    BufferedReader reader;  

    public MergeEntry(String value, BufferedReader reader) {  
        this.value = value;  
        this.reader = reader;  
    }  

    @Override
    public int compareTo(MergeEntry o) {  
        returnthis.value.compareTo(o.value);  
    }  
}

五、分布式解決方案

1.分片策略設(shè)計(jì)

2.Spark實(shí)現(xiàn)方案

val qqRDD = spark.read.textFile("hdfs://qq_data/*.txt")  
  .map(_.toLong)  
  .repartition(1000)  // 分為1000個(gè)分區(qū)  

// 每個(gè)分區(qū)內(nèi)部去重  
val distinctRDD = qqRDD.mapPartitions { iter =>  
val bitmap = newRoaringBitmap()  
  iter.foreach(qq => bitmap.add(qq.toInt))  
  bitmap.iterator.asScala.map(_.toLong)  
}  

// 全局去重(可選)  
val globalDistinct = distinctRDD.distinct()  

globalDistinct.saveAsTextFile("hdfs://result/")

3.內(nèi)存優(yōu)化:RoaringBitmap

存儲(chǔ)優(yōu)勢(shì)對(duì)比

普通位圖:10^10 / 8 / 1024/1024 ≈ 1.16 GB  
RoaringBitmap:稀疏數(shù)據(jù)下可壓縮至100-300 MB

六、生產(chǎn)級(jí)架構(gòu):Lambda架構(gòu)

1.系統(tǒng)架構(gòu)圖

2.各層技術(shù)選型

架構(gòu)層

技術(shù)棧

處理目標(biāo)

批處理層

Spark + HDFS

全量數(shù)據(jù)去重

速度層

Flink + Redis

實(shí)時(shí)增量去重

服務(wù)層

Spring Boot + HBase

統(tǒng)一查詢接口

3.實(shí)時(shí)去重實(shí)現(xiàn)

public class QQDeduplication {  
    privatestaticfinal String REDIS_KEY = "qq_set";  

    public boolean isDuplicate(String qq) {  
        try (Jedis jedis = jedisPool.getResource()) {  
            // 使用HyperLogLog進(jìn)行基數(shù)估計(jì)  
            if (jedis.pfcount(REDIS_KEY) > 1_000_000_000L) {  
                returntrue; // 已超過(guò)10億,直接返回重復(fù)  
            }  
            return jedis.sadd(REDIS_KEY, qq) == 0;  
        }  
    }  
}

七、終極方案:分層位圖索引

1.架構(gòu)設(shè)計(jì)

2.存儲(chǔ)計(jì)算

QQ號(hào)范圍:10000 - 9999999999(約100億)分層設(shè)計(jì)

  • 第一層分片:100個(gè)區(qū)間(每區(qū)間1億)
  • 第二層分片:100個(gè)子區(qū)間(每區(qū)間100萬(wàn))
  • 第三層存儲(chǔ):RoaringBitmap(每分區(qū)1.2MB)

總內(nèi)存需求

100 × 100 × 1.2MB = 12GB(分布式存儲(chǔ)可行)

3.Java實(shí)現(xiàn)

public class LayeredBitmap {  
    privatefinal RoaringBitmap[][][] bitmaps;  
    privatestaticfinalint L1 = 100; // 一級(jí)分片  
    privatestaticfinalint L2 = 100; // 二級(jí)分片  

    public LayeredBitmap() {  
        bitmaps = new RoaringBitmap[L1][L2][];  
    }  

    public void add(long qq) {  
        int l1Index = (int)((qq - 10000) / 100_000_000);  
        long remainder = (qq - 10000) % 100_000_000;  
        int l2Index = (int)(remainder / 1_000_000);  
        int value = (int)(remainder % 1_000_000);  

        if (bitmaps[l1Index][l2Index] == null) {  
            bitmaps[l1Index][l2Index] = new RoaringBitmap();  
        }  
        bitmaps[l1Index][l2Index].add(value);  
    }  

    public boolean contains(long qq) {  
        // 類似add的分片計(jì)算  
        RoaringBitmap bitmap = bitmaps[l1Index][l2Index];  
        return bitmap != null && bitmap.contains(value);  
    }  
}

八、方案對(duì)比與選型建議

方案

適用場(chǎng)景

內(nèi)存/存儲(chǔ)

時(shí)間復(fù)雜度

精度

單機(jī)位圖

<1億數(shù)據(jù)

O(n)

O(1)

100%

布隆過(guò)濾器

百億級(jí)容忍誤差

O(1)

O(k)

<99.9%

外部排序

單機(jī)磁盤處理

磁盤空間

O(n log n)

100%

Spark分布式

海量數(shù)據(jù)批量處理

集群存儲(chǔ)

O(n)

100%

Redis實(shí)時(shí)去重

增量數(shù)據(jù)實(shí)時(shí)處理

O(n)

O(1)

100%

分層位圖索引

超大規(guī)模精準(zhǔn)去重

O(n)壓縮存儲(chǔ)

O(1)

100%

九、實(shí)戰(zhàn)經(jīng)驗(yàn)與避坑指南

1.數(shù)據(jù)傾斜解決方案

問題場(chǎng)景:部分QQ號(hào)段過(guò)于集中(如100000-199999)

解決策略

// 動(dòng)態(tài)分片函數(shù)  
int getShardId(long qq, int shardCount) {  
    String str = String.valueOf(qq);  
    // 取后6位作為分片依據(jù)  
    int suffix = Integer.parseInt(str.substring(Math.max(0, str.length() - 6)));  
    return suffix % shardCount;  
}

2.去重精度保障

3.成本優(yōu)化建議

  • 冷熱分離:熱數(shù)據(jù)用內(nèi)存位圖,冷數(shù)據(jù)存磁盤
  • 壓縮存儲(chǔ):使用RoaringBitmap替代普通位圖
  • 分級(jí)存儲(chǔ)

a.最近3個(gè)月數(shù)據(jù):內(nèi)存存儲(chǔ)

b.歷史數(shù)據(jù):HBase+壓縮

總結(jié)

  • 分治思想:10億問題拆解為1000個(gè)100萬(wàn)問題
  • 空間換時(shí)間:位圖法用存儲(chǔ)空間換取O(1)時(shí)間復(fù)雜度
  • 概率智慧:布隆過(guò)濾器用可控誤差換取千倍空間壓縮
  • 分層設(shè)計(jì):億級(jí)→百萬(wàn)級(jí)→萬(wàn)級(jí)分層處理
  • 動(dòng)靜分離:批處理處理歷史數(shù)據(jù),實(shí)時(shí)處理增量數(shù)據(jù)

10億QQ號(hào)去重的本質(zhì),是將問題拆解到每個(gè)計(jì)算單元都能高效處理的粒度。

責(zé)任編輯:姜華 來(lái)源: 蘇三說(shuō)技術(shù)
相關(guān)推薦

2021-10-08 11:13:41

子集問題數(shù)據(jù)結(jié)構(gòu)算法

2017-10-16 13:45:04

2024-07-08 00:00:01

多線程ThreadC#

2023-03-21 07:39:51

CentOS掛載硬盤

2023-01-13 17:02:10

操作系統(tǒng)鴻蒙

2023-02-28 07:39:18

2024-12-03 00:38:37

數(shù)據(jù)湖存儲(chǔ)COS

2025-01-16 16:41:00

ObjectConditionJDK

2024-10-05 00:00:00

HTTPS性能HTTP/2

2024-02-23 08:09:43

Rediskey名字數(shù)據(jù)庫(kù)

2024-10-15 10:32:30

2024-06-20 08:06:30

2023-04-26 10:21:04

2024-04-30 09:02:48

2023-12-20 08:23:53

NIO組件非阻塞

2023-12-12 08:41:01

2024-04-07 00:00:00

ESlint命令變量

2024-05-28 09:12:10

2023-01-09 08:00:41

JavaScript閉包

2024-07-17 08:12:06

點(diǎn)贊
收藏

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