經典大數據面試題:兩個檔案各 50 億 URL,每 URL 64 字節,記憶體限制 4GB,找出共同 URL。單檔約 320GB,遠超記憶體,需採用分治策略。
# 對檔案 A 分桶
for each url in file_A:
bucket = hash(url) % 1000
write url to bucket_A[bucket]
# 對檔案 B 分桶(相同哈希函數)
for each url in file_B:
bucket = hash(url) % 1000
write url to bucket_B[bucket]
a0 vs b0, a1 vs b1 ... a999 vs b999for i in 0..999:
# 載入較小桶建立 HashSet
hashset = new HashSet()
for url in bucket_A[i]:
hashset.add(url)
# 掃描另一桶查找共同項
for url in bucket_B[i]:
if hashset.contains(url):
output url to result_file
# 釋放記憶體
hashset.clear()
將 1000 個結果檔合併為最終答案。
| 問題 | 解決方案 | |
|---|---|---|
| 桶分布不均(熱點桶過大) | 對過大桶遞歸再分桶(如再模 100) | |
| HashSet 記憶體溢出 | 使用 Bloom Filter 預過濾、或改用磁碟排序+歸併 | |
| URL 平均長度非固定 64B | 實際按行讀取,不依賴固定長度 | |
| 哈希碰撞導致錯誤 | 使用 64 位或 128 位哈希(如 MurmurHash3, xxHash) |
| 指標 | 分桶法 | 外部排序法 |
|---|---|---|
| 時間複雜度 | O(N) | O(N log N) |
| 空間複雜度 | O(N/buckets) | O(N/buckets) 排序緩衝 |
| 磁碟 IO | 2次讀寫(分桶+處理) | 多次讀寫(排序輪次) |
| 實現難度 | 中等 | 較高(需外部排序) |
分桶法是工程上最常用的方案,結合 Bloom Filter 預過濾與遞歸分桶處理傾斜,能穩健解決 TB 級別的大數據去重/交集問題。