← 回首頁

串流概要(Count-Min Sketch + HyperLogLog)

資料像水流般不斷湧來時——每秒上百萬次點擊、上億個訪客——你根本存不下每一筆,卻又想知道「某個東西出現了 幾次」和「總共有幾個不一樣的東西」。這兩種串流概要(sketch)就是用一點點固定空間換一個夠準的估計: Count-Min Sketch 像幾排共用的計數格子,同一格會被不同東西擠著用,所以估出來只會多、不會少; HyperLogLog 則像看賭桌上「有人連丟出一長串正面」的罕見巧合,反推現場一定人很多。下面兩節都會把 「估計值」和「獨立算出的真正答案」並排,讓你親眼看見它們差多少。

兩者都是在固定小空間內近似串流統計量的機率性資料結構,用精確度換取規模:Count-Min Sketch 以 d×w 計數矩陣 逐事件更新,點查詢時對每一列取命中格計數的最小值作為頻次估計——因不同鍵可能雜湊到同一格造成碰撞,估計值 只會「高估或持平」,絕不「低估」真實頻次;HyperLogLog 則對每個事件的雜湊值取前導零位置(ρ),存進固定 數量的暫存器並只升不降地更新,再由全部暫存器獨立重算調和平均公式估計相異值個數(基數),教學用小參數下 偏差明顯,但方向不固定(可能高估也可能低估)。本頁兩個 section 皆同時揭露「估計值」與「獨立重算的真實值」, 誠實對照兩者差距。

為什麼 AI 時代重要

觀測系統(observability)處理巨量請求流量時,無法為每個 API/服務組合維護精確計數器,Count-Min Sketch 用固定小空間近似統計流量頻次,支撐即時告警與限流判斷;LLM 訓練資料清洗常需要依 token/n-gram 出現頻次 過濾低頻雜訊或高頻重複樣本,逐一精確計數在十億級語料上不可行,只能容忍「只會高估」的近似頻次;而估計 十億級使用者/IP/去重樣本數(基數)時,精確去重需要儲存全部相異值,HyperLogLog 只用固定數量的暫存器, 以有偏差但誠實可控的方式換取常數空間。

它是 Bloom Filter 的延伸

Bloom Filter 只用位元陣列回答「是否存在」;Count-Min Sketch 把位元陣列換成計數矩陣,回答「大約出現幾次」 (只會高估,原理同 Bloom Filter 的碰撞——只是碰撞混入的是其他鍵的計數貢獻而非置位訊號);HyperLogLog 則把雜湊值的前導零位置存進固定數量的暫存器,回答「大約有幾個相異值」。三者同屬「用雜湊格位換取空間、 犧牲部分精確度」的機率性資料結構家族 → 雜湊 Hash Table / Bloom Filter

1. Count-Min Sketch(計數矩陣 + min 查詢)

buildMatrix:對每個到達事件 x,依固定雜湊族 h_i(x) = ((A[i]·x + B[i]) mod 17) mod 8(i=0..2,共 D=3 個 雜湊函式,每列 W=8 格,A/B 皆為固定參數表)在每一列各選一格計數 +1;query:對每個查詢鍵,獨立由矩陣 終態取每一列命中格的最小值作為頻次估計,並與獨立 Map 全掃得到的真實頻次同幀對照。因為不同鍵可能雜湊到 同一格(碰撞),格內計數會混入其他鍵的貢獻,估計值恆 >= 真實頻次,只會高估或持平,絕不低估。

固定事件串流(token id):[5,12,5,7,12,5,3,12,5,9,12,5,7,12,3](15 事件,熱鍵 5/12 重複出現); 查詢鍵:[5,12,7,3,9,11](11 為未出現鍵,真實頻次為 0,CMS 仍可能因碰撞估出 >0)。矩陣 D=3×W=8, MOD=17,A=[1,3,5],B=[5,0,1](固定雜湊族,對照 Java CountMinSketch.java)。
已更新格數(updates):0 階段:updates
列=雜湊函式 row0..row2(D=3)、欄=桶 0..7(W=8);格值=該列該桶目前計數(從 0 起,非空格語意)。 藍色外框(active)=當前事件/查詢命中的格;查詢階段粉紅(pivot)=取得最小值的格(第一個達到最小值 的列)。只會高估,絕不低估:碰撞(不同鍵雜湊到同一格)使該格計數混入其他鍵的貢獻,估計值 (取各列 min)恆 >= 真實頻次——碰撞範例 key=12:est=6 > true=5。

估計 vs 真實頻次 對照

查詢鍵估計 est真實 true高估量

已執行操作紀錄(opLog)

2. HyperLogLog(前導零暫存器 + 基數估計)

buildRegisters:對每個到達事件 x,以 16-bit 決定性雜湊 H(x) = ((2691·x + 479) mod 65537) & 0xFFFF 取前 REG_BITS=3 位選暫存器索引(m=8 個暫存器)、其餘位計算前導零 rank(ρ),並以 max(目前值, ρ) 更新 暫存器(只升不降)。estimate:由暫存器終態獨立重算調和平均公式 E = alpha_m·m²/Σ(2^-register[j]), 當 raw 值偏小且存在空暫存器時,改用 linear counting 公式修正。真實基數則由獨立 Set 全程計數相異值。

固定事件串流(同 Count-Min Sketch 一節):[5,12,5,7,12,5,3,12,5,9,12,5,7,12,3](相異值 5/7/9/12/3 共 5 個)。REG_BITS=3(m=8 暫存器),16-bit 決定性雜湊 H(x)=((2691·x+479) mod 65537)&0xFFFF(固定 參數表,對照 Java HyperLogLog.java)。
已處理事件數(updates):0
唯一 1 列 × 8 欄的暫存器列(m=8=2^REG_BITS);格值=該暫存器目前的最大 ρ(前導零 rank,從 0 起, 非空格語意)。藍色外框(active)=當前事件命中的暫存器。暫存器只升不降(單調)教學用小參數誤差大:m=8 時估計值可能明顯偏離真實基數(可能高估也可能低估,方向不固定, 這是小參數的正常教學可視現象而非估計失準);raw 調和平均值過小且存在空暫存器時會觸發 linear counting 修正;生產環境建議 m 從 2^14 起以壓低誤差。

估計 vs 真實基數 即時對照

項目數值
估計 estimate0.000
真實 trueCardinality0
差值(estimate − true)0.000

暫存器(registers)

已執行操作紀錄(opLog)