Salta al contenuto
Note per Studenti Esercizio - Dimensionamento di un filtro di Bloom e fingerprint di documenti

Esercizio - Dimensionamento di un filtro di Bloom e fingerprint di documenti

Teoria: Hashing randomizzato - famiglie universali, filtri di Bloom e fingerprintHashing con catene e costo atteso 1+alfa; famiglie universali (probabilità di collisione al più 1/m) e costruzione h(x)=((ax+b) mod p) mod m con dimostrazione; hashing perfetto a due livelli (spazio lineare, ricerca O(1) nel caso peggiore); filtri di Bloom: falsi positivi (1-e^(-kn/m))^k e k ottimo (m/n) ln 2; fingerprint di stringhe e numero di bit necessari.Hashing randomizzato - famiglie universali, filtri di Bloom e fingerprint → (filtri di Bloom, fingerprint), Palline e urne - compleanno, carico massimo e approssimazione di PoissonModello palline e urne (m palline, n urne, scelte indipendenti e uniformi): paradosso del compleanno con soglia sqrt(2 n ln 2), urne vuote attese n e^(-m/n), carico massimo ln n / ln ln n con dimostrazione (first moment e union bound), approssimazione di Poisson con il fattore e sqrt(m), potere delle due scelte (ln ln n / ln 2).Palline e urne - compleanno, carico massimo e approssimazione di Poisson → (collisioni).

Testo. Un crawler deve ricordare n=105n=10^5 indirizzi già visitati con un filtro di Bloom, accettando una frazione di falsi positivi (pagine ritenute già viste ma nuove) del 1%1\%.

  1. Quanti bit per elemento e quanti bit totali mm servono, e quale kk? Quanti byte? Confrontare con la memorizzazione di 10510^5 chiavi da 6464 bit.
  2. Calcolare il tasso di falsi positivi esatto (1−(1−1m)kn)k(1-(1-\frac1m)^{kn})^k per k=5,6,7,8,10k=5,6,7,8,10 con questo mm.
  3. Con m=10nm=10n bit calcolare il kk ottimo intero e il tasso di falsi positivi; con m=8nm=8n idem.
  4. Dimostrare che il kk che minimizza (1−e−kn/m)k(1-e^{-kn/m})^k è mnln⁡2\frac mn\ln2.
  5. Fingerprint. Si vogliono identificare n=106n=10^6 documenti con una fingerprint di bb bit, con probabilità di una collisione tra due documenti qualsiasi ≤10−3\le10^{-3}. Quanti bit? E per confrontare due stringhe di lunghezza 10610^6 con la fingerprint polinomiale modulo p=261−1p=2^{61}-1 qual è la probabilità di errore massima?
  6. Verificare con una simulazione il tasso di falsi positivi del punto 2 (modello idealizzato: ogni elemento accende kk bit uniformi).

Soluzione

1. Dimensionamento. Il tasso ottimo è f=2−k=0,6185m/nf=2^{-k}=0{,}6185^{m/n}, quindi mn=log⁡2(1/f)ln⁡2=log⁡21000,6931=6,6440,6931=9,585 bit per elemento.\frac mn=\frac{\log_2(1/f)}{\ln2}=\frac{\log_2100}{0{,}6931}=\frac{6{,}644}{0{,}6931}=9{,}585\text{ bit per elemento}. m=⌈9,585⋅105⌉=958 506m=\lceil9{,}585\cdot10^5\rceil=\boxed{958\,506} bit =119 814=119\,814 byte ≈117\approx117 KiB. Il kk ottimo è 9,585⋅ln⁡2=6,649{,}585\cdot\ln2=6{,}64, quindi k=7\boxed{k=7}. Le chiavi da 6464 bit occupano 800 000800\,000 byte: il filtro è 6,76{,}7 volte più piccolo.

2. Tasso esatto. Con m=958 506m=958\,506:

kk 55 66 77 88 1010
ff 0,011090{,}01109 0,010140{,}01014 0,010040{,}01004 0,010530{,}01053 0,013000{,}01300

Il minimo è a k=7k=7 con f=0,01004f=0{,}01004, appena sopra l'1%1\% per l'arrotondamento di kk; chi vuole stare sotto l'1%1\% aggiunge un po' di bit (m=960 000m=960\,000).

3. Altri rapporti. Con m=10nm=10n: kk ottimo reale 6,93→76{,}93\to7 e f=(1−(1−10−6)7⋅105)7=0,00819f=(1-(1-10^{-6})^{7\cdot10^5})^7=\boxed{0{,}00819} (con k=6k=6: 0,008440{,}00844; k=8k=8: 0,008460{,}00846; k=3k=3: 0,01740{,}0174). Con m=8nm=8n: kk reale 5,555{,}55, il minimo intero è k=6k=6 con f=0,0216f=\boxed{0{,}0216} (k=5k=5: 0,02170{,}0217; k=7k=7: 0,02290{,}0229). Il minimo è piatto: scostarsi di uno da kk ottimo costa pochissimo.

4. Ottimizzazione. Sia q=e−kn/mq=e^{-kn/m} (frazione di bit a 00): allora k=−mnln⁡qk=-\frac mn\ln q e ln⁡f=kln⁡(1−q)=−mn ln⁡qln⁡(1−q)\ln f=k\ln(1-q)=-\frac mn\,\ln q\ln(1-q). Bisogna massimizzare g(q)=ln⁡qln⁡(1−q)g(q)=\ln q\ln(1-q) su (0,1)(0,1). È simmetrica (g(q)=g(1−q)g(q)=g(1-q)) e g′(q)=ln⁡(1−q)q−ln⁡q1−qg'(q)=\frac{\ln(1-q)}q-\frac{\ln q}{1-q} si annulla in q=12q=\frac12 (dove i due termini sono uguali), che per simmetria è un estremo; a q→0,1q\to0,1 si ha g→0g\to0 e g>0g>0 dentro: è un massimo, con g(12)=ln⁡22g(\frac12)=\ln^22. Quindi ln⁡fmin⁡=−mnln⁡22\ln f_{\min}=-\frac mn\ln^22, e−kn/m=12  ⟺  k=mnln⁡2e^{-kn/m}=\frac12\iff\boxed{k=\frac mn\ln2} e fmin⁡=2−kf_{\min}=2^{-k}. Con kk ottimo metà dei bit è a 11.

5. Fingerprint. Il numero di coppie è (n2)≈5⋅1011\binom n2\approx5\cdot10^{11} e ognuna collide con probabilità 2−b2^{-b}: per l'union bound P≤n22b+1P\le\frac{n^2}{2^{b+1}}. Si vuole ≤10−3\le10^{-3}: 2b≥10122⋅10−3=5⋅10142^b\ge\frac{10^{12}}{2\cdot10^{-3}}=5\cdot10^{14}, b≥log⁡25⋅1014=48,83b\ge\log_25\cdot10^{14}=48{,}83, quindi b=49\boxed{b=49} (con b=48b=48: 1,78⋅10−31{,}78\cdot10^{-3}; b=40b=40: 0,450{,}45; b=64b=64: 2,7⋅10−82{,}7\cdot10^{-8}). Per due stringhe di lunghezza ℓ=106\ell=10^6 la fingerprint ϕ(s)=∑sixi mod p\phi(s)=\sum s_ix^i\bmod p con xx uniforme in Zp\mathbb Z_p: la differenza è un polinomio non nullo di grado <ℓ<\ell, che ha al più ℓ−1\ell-1 radici in Zp\mathbb Z_p (un polinomio di grado dd ne ha al più dd), quindi P(errore)≤ℓ−1p=999 999261−1=4,3⋅10−13P(\text{errore})\le\frac{\ell-1}p=\frac{999\,999}{2^{61}-1}=\boxed{4{,}3\cdot10^{-13}}.

6. Simulazione. Con n=105n=10^5, m=958 506m=958\,506 e 300 000300\,000 interrogazioni di elementi non inseriti (modello idealizzato): k=6k=6: 0,010270{,}01027 (formula 0,010140{,}01014); k=7k=7: 0,010180{,}01018 (formula 0,010040{,}01004); k=10k=10: 0,013020{,}01302 (formula 0,013000{,}01300). La frazione di bit a 11 con k=7k=7 è 0,5180{,}518 (attesa 1−e−7⋅105/958506=0,5181-e^{-7\cdot10^5/958506}=0{,}518). La simulazione conferma la formula entro l'errore statistico (≈2⋅10−4\approx2\cdot10^{-4}).

Codice di verifica

python
import numpy as np
from math import ceil, log, log2, exp

n = 10 ** 5
m = ceil(n * log2(100) / log(2))                    # 958506
f = lambda m, k, n=n: (1 - (1 - 1 / m) ** (k * n)) ** k
print(m, m / 8, [round(f(m, k), 5) for k in (5, 6, 7, 8, 10)])
print([round(f(10 * n, k), 5) for k in (3, 6, 7, 8)], [round(f(8 * n, k), 5) for k in (5, 6, 7)])
print([10 ** 12 / 2 ** (b + 1) for b in (48, 49, 64)], 999999 / (2 ** 61 - 1))

rng = np.random.default_rng(9)
for k in (6, 7, 10):
    bit = np.zeros(m, dtype=bool)
    bit[rng.integers(0, m, size=(n, k)).ravel()] = True      # ogni elemento accende k bit
    q = rng.integers(0, m, size=(300_000, k))                # interrogazioni di elementi nuovi
    print(k, bit.mean(), bit[q].all(axis=1).mean())

Risultato: 958506 119813.25 [0.01109, 0.01014, 0.01004, 0.01053, 0.013], [0.01741, 0.00844, 0.00819, 0.00846] [0.02168, 0.02158, 0.02293] e [0.00178, 0.00089, 2.7e-08] 4.3e-13 (limiti per b=48,49,64b=48,49,64 e fingerprint di stringhe), poi tre righe con la frazione di bit a 11 e il tasso osservato (≈0,01\approx0{,}01-0,0130{,}013).

Versione ripasso

  • Dimensionamento (n=105n=10^5, f=1%f=1\%): mn=log⁡2(1/f)ln⁡2=9,585\frac mn=\frac{\log_2(1/f)}{\ln2}=9{,}585 bit/elemento, m=958 506m=958\,506 bit (119 814119\,814 byte, 117117 KiB), k=9,585ln⁡2=6,64→7k=9{,}585\ln2=6{,}64\to7; chiavi da 6464 bit: 800 000800\,000 byte (6,76{,}7 volte di più) (Hashing randomizzato - famiglie universali, filtri di Bloom e fingerprintHashing con catene e costo atteso 1+alfa; famiglie universali (probabilità di collisione al più 1/m) e costruzione h(x)=((ax+b) mod p) mod m con dimostrazione; hashing perfetto a due livelli (spazio lineare, ricerca O(1) nel caso peggiore); filtri di Bloom: falsi positivi (1-e^(-kn/m))^k e k ottimo (m/n) ln 2; fingerprint di stringhe e numero di bit necessari.Hashing randomizzato - famiglie universali, filtri di Bloom e fingerprint →).
  • Tasso esatto (1−(1−1m)kn)k(1-(1-\frac1m)^{kn})^k con quel mm: k=5,6,7,8,10k=5,6,7,8,10 dà 0,01109; 0,01014; 0,01004; 0,01053; 0,013000{,}01109;\ 0{,}01014;\ 0{,}01004;\ 0{,}01053;\ 0{,}01300. Con m=10nm=10n: k=7k=7, 0,008190{,}00819 (k=3k=3: 0,01740{,}0174); con m=8nm=8n: k=6k=6, 0,02160{,}0216.
  • Ottimo. q=e−kn/mq=e^{-kn/m}, ln⁡f=−mnln⁡qln⁡(1−q)\ln f=-\frac mn\ln q\ln(1-q); g(q)=ln⁡qln⁡(1−q)g(q)=\ln q\ln(1-q) è simmetrica, massima in q=12q=\frac12 con valore ln⁡22\ln^22: k=mnln⁡2k=\frac mn\ln2, f=2−kf=2^{-k}, metà dei bit a 11.
  • Fingerprint. P≤n22b+1P\le\frac{n^2}{2^{b+1}}; n=106n=10^6 e 10−310^{-3}: 2b≥5⋅10142^b\ge5\cdot10^{14}, b=49b=49 (b=48b=48: 1,78⋅10−31{,}78\cdot10^{-3}; b=64b=64: 2,7⋅10−82{,}7\cdot10^{-8}). Stringhe di lunghezza ℓ=106\ell=10^6 con ϕ(s)=∑sixi mod p\phi(s)=\sum s_ix^i\bmod p, p=261−1p=2^{61}-1: errore ≤ℓ−1p=4,3⋅10−13\le\frac{\ell-1}p=4{,}3\cdot10^{-13} (polinomio non nullo di grado <ℓ<\ell, al più ℓ−1\ell-1 radici).
  • Simulazione (modello ideale, 3⋅1053\cdot10^5 interrogazioni): k=6,7,10k=6,7,10 dà 0,01027; 0,01018; 0,013020{,}01027;\ 0{,}01018;\ 0{,}01302; bit a 11 con k=7k=7: 0,5180{,}518.
  • Errori tipici. Usare kk non intero senza arrotondare; confondere mm (bit totali) con m/nm/n; dimenticare che il filtro non ha falsi negativi ma non supporta la cancellazione.

Teoria collegata