Qual è il vantaggio nell'usare i filtri bloom?


108

Sto leggendo sui filtri bloom e sembrano semplicemente stupidi. Tutto ciò che puoi ottenere con un filtro bloom, potresti farlo in meno spazio, in modo più efficiente, utilizzando una singola funzione hash anziché più, o questo è quello che sembra. Perché dovresti usare un filtro bloom e come è utile?


5
hai letto l'articolo di wikipedia? Spiega abbastanza bene i vantaggi. en.wikipedia.org/wiki/Bloom_filter
Alex Budovski

@ David che sembra improbabile, però. k funzioni hash in uno spazio costante avranno molte più collisioni di una singola funzione hash in uno spazio costante.
mal di testa

1
@Alex Ho letto l'articolo di wikipedia. Capisco cosa si dice lì, ma non capisco perché sia ​​affatto meglio. Perché funziona è intuitivo. Perché è utile non lo è.
mal di testa

Questo scrittore fa un ottimo lavoro con esso michaelnielsen.org/ddi/why-bloom-filters-work-the-way-they-do
dranxo

2
@dranxo, L'articolo collegato jasondavies.com/bloomfilter è migliore.
Pacerier

Risposte:


155

Da Wikipedia :

I filtri Bloom hanno un notevole vantaggio in termini di spazio rispetto ad altre strutture di dati per la rappresentazione di insiemi, come alberi di ricerca binari autobilanciati, tentativi, tabelle hash o array semplici o elenchi collegati delle voci. La maggior parte di questi richiedono la memorizzazione almeno degli elementi di dati stessi, che può richiedere ovunque da un piccolo numero di bit, per piccoli interi, a un numero arbitrario di bit, come per le stringhe (i tentativi sono un'eccezione, poiché possono condividere l'archiviazione tra elementi con prefissi uguali). Le strutture collegate comportano un overhead di spazio lineare aggiuntivo per i puntatori. Un filtro Bloom con 1% di errore e un valore ottimale di k, d'altra parte, richiede solo circa 9,6 bit per elemento, indipendentemente dalla dimensione degli elementi. Questo vantaggio deriva in parte dalla sua compattezza, ereditata dagli array, e in parte dalla sua natura probabilistica. Se un tasso di falsi positivi dell'1% sembra troppo alto, ogni volta che aggiungiamo circa 4,8 bit per elemento lo riduciamo di dieci volte.

Abbastanza chiaro per me.

Un filtro bloom non memorizza gli elementi stessi, questo è il punto cruciale. Non si utilizza un filtro fioritura per verificare se un elemento è presente, lo si utilizza per verificare se è certamente non è presente, in quanto garantisce nessun falso negativo. Ciò consente di non eseguire operazioni aggiuntive per elementi che non esistono in un set (come l'IO del disco per cercarli).

E tutto in uno spazio significativamente inferiore rispetto a qualcosa come una tabella hash (che probabilmente sarà parzialmente su disco per grandi set di dati). Sebbene tu possa utilizzare un filtro bloom in combinazione con una struttura come una tabella hash, una volta che sei certo che l'elemento abbia una possibilità di essere presente.

Quindi un modello di utilizzo di esempio potrebbe essere:

Hai molti dati, su disco: decidi tu quale limite di errore vuoi (es. 1%), che prescrive il valore di m . Quindi viene determinato il k ottimo (dalla formula data nell'articolo). Si popola il filtro da questi dati associati al disco una volta.

Ora hai il filtro nella RAM. Quando è necessario elaborare un elemento, si interroga il filtro per vedere se esiste una possibilità di esistere nel set di dati. In caso contrario, non viene svolto alcun lavoro aggiuntivo. Nessuna lettura del disco, ecc. (Cosa che dovresti fare se fosse un hash o un albero, ecc.).

Altrimenti, se il filtro dice "Sì, c'è dentro", c'è una probabilità dell'1% che sia sbagliato, quindi fai il lavoro necessario per scoprirlo. Il 99% del tempo, in realtà sarà essere lì, in modo che il lavoro non è stato per nulla.


2
Se è chiaro, rispondi. Come potrebbe essere più efficiente in termini di spazio di una singola funzione hash sullo stesso set di dimensioni? Questo creerà semplicemente più collisioni. Rimbalzerai cercando su funzioni hash separate per assicurarti di avere un 1 in tutte le funzioni hash. Non capisco che sia un vantaggio rispetto all'utilizzo di una singola funzione hash.
mal di testa

19
Una funzione hash è codice, non dati. Con cosa intendi utilizzare la funzione hash? Un tavolo da hash? In tal caso, la tabella dovrà memorizzare le chiavi, che potrebbero essere di dimensioni arbitrarie, a differenza di un filtro bloom. L'estratto lo menziona.
Alex Budovski

3
Considera un filtro bloom con una sola funzione hash, anziché k. Qual è il vantaggio di aggiungere più funzioni hash? Questo creerà semplicemente più collisioni. O mi sbaglio?
mal di testa

2
Ciò trova risposta nell'ultimo paragrafo in "Vantaggi di spazio e tempo" nell'articolo di Wikipedia e nella sezione "Probabilità di falsi positivi".
Alex Budovski

4
Ha appena cliccato. Grazie mille, questo mi ha infastidito per un po '. Diminuisce il numero di falsi positivi perché un falso positivo dovrebbe a) essere una collisione su tutte le tue funzioni hash oppure b) tutti gli spazi sono stati riempiti da altri valori. La scelta della taglia deve essere un processo complicato quindi, immagino. Correggimi se sbaglio, ma penso di aver capito. Grazie a tutti.
mal di testa

156

Alex lo ha spiegato abbastanza bene. Per coloro che ancora non l'hanno capito, si spera che questo esempio ti aiuti a capire:

Diciamo che lavoro per Google, nel team di Chrome, e voglio aggiungere una funzionalità al browser che avvisa l'utente se l'URL che ha inserito è un URL dannoso. Quindi ho un set di dati di circa 1 milione di URL dannosi, la dimensione di questo file è di circa 25 MB. Poiché la dimensione è abbastanza grande (grande rispetto alla dimensione del browser stesso), memorizzo questi dati su un server remoto.

Caso 1: utilizzo una funzione hash con una tabella hash. Decido su una funzione di hashing efficiente ed eseguo tutti i 1 milione di URL attraverso la funzione di hashing per ottenere chiavi hash. Quindi creo una tabella hash (un array), dove la chiave hash mi darebbe l'indice per posizionare quell'URL. Quindi ora una volta che ho eseguito l'hashing e ho riempito la tabella di hashing, ne controllo le dimensioni. Ho memorizzato tutti 1 milione di URL nella tabella hash insieme alle loro chiavi. Quindi la dimensione è di almeno 25 MB. Questa tabella hash, a causa delle sue dimensioni, verrà archiviata su un server remoto. Quando un utente arriva e inserisce un URL nella barra degli indirizzi, devo controllare se è dannoso. Quindi eseguo l'URL attraverso la funzione hash (il browser stesso può farlo) e ottengo una chiave hash per quell'URL. Ora devo fare una richiesta al mio server remoto con quella chiave hash, per verificare se l'URL particolare nella mia tabella hash con quella particolare chiave, è lo stesso di quello che l'utente ha inserito. Se sì, allora è dannoso e in caso negativo non è dannoso. Pertanto, ogni volta che l'utente immette un URL, deve essere effettuata una richiesta al server remoto per verificare se si tratta di un URL dannoso. Ciò richiederebbe molto tempo e quindi rallenterebbe il mio browser.

Caso 2: utilizzo un filtro bloom. L'intero elenco di 1 milione di URL viene eseguito attraverso il filtro bloom utilizzando più funzioni hash e le rispettive posizioni sono contrassegnate come 1, in una vasta gamma di 0. Supponiamo di volere un tasso di falsi positivi dell'1%, utilizzando un calcolatore del filtro bloom ( http://hur.st/bloomfilter?n=1000000&p=0.01), otteniamo la dimensione del filtro bloom richiesto di soli 1,13 MB. Questa piccola dimensione è prevista poiché, anche se la dimensione dell'array è enorme, stiamo memorizzando solo 1 o 0 e non gli URL come nel caso della tabella hash. Questo array può essere trattato come un array di bit. Cioè, poiché abbiamo solo due valori 1 e 0, possiamo impostare singoli bit invece di byte. Ciò ridurrebbe lo spazio occupato di 8 volte. Questo filtro bloom da 1,13 MB, a causa delle sue piccole dimensioni, può essere memorizzato nel browser web stesso !! Pertanto, quando un utente arriva e inserisce un URL, applichiamo semplicemente le funzioni hash richieste (nel browser stesso) e controlliamo tutte le posizioni nel filtro bloom (che è memorizzato nel browser). Un valore 0 in una qualsiasi delle posizioni ci dice che questo URL NON è SICURAMENTE nell'elenco degli URL dannosi e l'utente può procedere liberamente. Pertanto non abbiamo effettuato una chiamata al server e quindi abbiamo risparmiato tempo. Un valore di 1 ci dice che l'URL POTREBBE essere nell'elenco di URL dannosi. In questi casi facciamo una chiamata al server remoto e da lì possiamo usare qualche altra funzione hash con qualche tabella hash come nel primo caso per recuperare e controllare se l'URL è effettivamente presente. Poiché la maggior parte delle volte, è improbabile che un URL sia dannoso, il piccolo filtro bloom nel browser lo capisce e quindi fa risparmiare tempo evitando le chiamate al server remoto. Solo in alcuni casi, se il filtro bloom ci dice che l'URL POTREBBE essere dannoso, solo in quei casi effettuiamo una chiamata al server. Quel "MIGHT" è corretto al 99%. In questi casi facciamo una chiamata al server remoto e da lì possiamo usare qualche altra funzione hash con qualche tabella hash come nel primo caso per recuperare e controllare se l'URL è effettivamente presente. Poiché la maggior parte delle volte, è improbabile che un URL sia dannoso, il piccolo filtro bloom nel browser lo capisce e quindi fa risparmiare tempo evitando le chiamate al server remoto. Solo in alcuni casi, se il filtro bloom ci dice che l'URL POTREBBE essere dannoso, solo in quei casi effettuiamo una chiamata al server. Quel "MIGHT" è corretto al 99%. In questi casi facciamo una chiamata al server remoto e da lì possiamo usare qualche altra funzione hash con qualche tabella hash come nel primo caso per recuperare e controllare se l'URL è effettivamente presente. Poiché la maggior parte delle volte, è improbabile che un URL sia dannoso, il piccolo filtro bloom nel browser lo capisce e quindi fa risparmiare tempo evitando le chiamate al server remoto. Solo in alcuni casi, se il filtro bloom ci dice che l'URL POTREBBE essere dannoso, solo in quei casi effettuiamo una chiamata al server. Quel "MIGHT" è corretto al 99%. il piccolo filtro bloom nel browser lo capisce e quindi fa risparmiare tempo evitando le chiamate al server remoto. Solo in alcuni casi, se il filtro bloom ci dice che l'URL POTREBBE essere dannoso, solo in quei casi effettuiamo una chiamata al server. Quel "MIGHT" è corretto al 99%. il piccolo filtro bloom nel browser lo capisce e quindi fa risparmiare tempo evitando le chiamate al server remoto. Solo in alcuni casi, se il filtro bloom ci dice che l'URL POTREBBE essere dannoso, solo in quei casi effettuiamo una chiamata al server. Quel "MIGHT" è corretto al 99%.

Quindi, utilizzando un piccolo filtro bloom nel browser, abbiamo risparmiato molto tempo poiché non è necessario effettuare chiamate al server per ogni URL inserito.

Possiamo vedere che la tabella hash con una singola funzione hash viene utilizzata per uno scopo completamente diverso rispetto a un filtro bloom. Spero che questo chiarisca i tuoi dubbi :)

modifica :

Ho implementato un filtro bloom per l'attività di test di URL dannosi in Python. Il codice può essere trovato qui - https://github.com/tarunsharma1/Bloom-Filter Il codice è molto semplice da capire e una descrizione dettagliata è fornita nel file readme.


3
Grazie per uno scenario di casi d'uso.
Squiggs.

1
Non ho ottenuto la parte dell'hashing e dell'associazione di un valore di 0 o 1. Se stiamo usando un array e memorizziamo 0 e 1 in questi, come cerchiamo il valore hash di un URL quando eseguiamo il test ?
divinedragon

1
Quindi fondamentalmente usiamo qualcosa chiamato funzione hash ... che accetta l'URL come stringa ... e fornisce un numero ... usiamo questo numero e impostiamo il valore dell'indice dell'array corrispondente su 1. Esistono diverse funzioni di hashing, ma ciò che è importante è che ogni volta che lo stesso URL viene passato attraverso una funzione di hashing, deve generare lo stesso numero. Un esempio di una funzione di hashing potrebbe essere la somma dei valori ASCII di tutti i caratteri in un URL. Nei filtri bloom utilizziamo molte funzioni di hashing e impostiamo tutti i valori dell'indice dell'array su 1. Spero che questo abbia chiarito i tuoi dubbi.
Tarun

1
Una tabella hash convenzionale come C # HashSet<String>utilizzerà 16 byte per elemento elemento nel migliore dei casi in cui la tabella hash è completamente piena: 4 byte mappati da un "bucket" a una voce in una tabella di voci (una matrice collegata singolarmente list), 4 byte per il codice hash memorizzato nella cache, 4 byte per il puntatore "successivo", 4 byte per un puntatore alla chiave. E questo non conta le dimensioni delle stringhe. Nel peggiore dei casi è di 40 byte: metà delle voci sono inutilizzate e 20 byte per voce una volta che il Stringpuntatore si espande a 8 byte per le architetture a 64 bit.
Qwertie

Non è necessario salvare la stringa stessa nel set di hash. Puoi salvarne l'hash come valore, rendendo l'hashset molto più piccolo. Quindi puoi giocare con la dimensione dell'hash: più è grande, minore sarà il tasso di falsi positivi.
user1028741

24

Inizierò con la spiegazione di cosa è un filtro bloom, cosa può e non può fare, perché ne abbiamo bisogno, mostrerò una descrizione intuitiva come funziona e poi fornirò qualche esempio quando possono essere utili.

Quindi un filtro bloom standard è una struttura dati probabilistica che può * :


  • aggiungi elemento a un set
  • controlla se un elemento è nell'insieme dicendo definitely not in the setopossibly in the set

Questo possibly in the setè esattamente il motivo per cui si chiama probabilistico. Usare parole intelligenti significa che sono possibili falsi positivi (ci possono essere casi in cui si pensa erroneamente che l'elemento sia positivo) ma i falsi negativi sono impossibili.

Ma non può * :

  • rimuovere un elemento dal set
  • darti un elenco di tutti gli elementi che sono attualmente nel tuo set

* Questo set di can / can't è per un filtro bloom di base. Poiché si tratta di una struttura dati utile creata molto tempo fa, le persone hanno scoperto come potenziarla con altre utili funzionalità.


Ma aspetta un attimo: conosciamo già una struttura dati che può rispondere a tutto questo senza vago "possibile" e anche senza tutte le limitazioni (non può rimuovere, non può mostrare tutto). E si chiama set . E qui arriva un vantaggio principale di un filtro bloom: è efficiente in termini di spazio e costante di spazio .

Ciò significa che non importa quanti elementi memorizziamo lì, lo spazio sarà lo stesso. Sì, un filtro bloom con 10^6elementi (filtro bloom inutile) occupa la stessa quantità di spazio di un filtro bloom con 10^20elementi e lo stesso spazio di un filtro bloom con 0elementi. Quindi quanto spazio ci vorrà? Sta a te decidere (ma c'è uno scambio di: più elementi hai più incerto sei con la possible in the setrisposta.

Un'altra cosa interessante è che è costante nello spazio. Quando salvi i dati in un set, devi effettivamente salvare questi dati. Quindi, se archivi, this long string in the setdevi utilizzare almeno 27 byte di spazio. Ma per un errore dell'1% e un valore ottimale di k ** , avrai bisogno di ~ 9,6 bit (<2 byte) per ogni elemento (sia che si tratti di un int breve o di un enorme muro di testo).

Un'altra proprietà è che tutte le operazioni richiedono tempo costante, che non è assolutamente la stessa cosa del tempo costante ammortizzato nel caso di set (ricorda che se il set ha collisioni, può deteriorarsi nel O(n)tempo).

** k è un valore delle funzioni hash utilizzate nel filtro bloom


Non descriverò come funzionano i filtri bloom (l'articolo di wikipedia fa un ottimo lavoro spiegando tutto). Qui dirò solo brevemente le basi.

  • si avvia un array di bit vuoto di lunghezza m
  • selezioni kdiverse funzioni hash (più indipendenti sono, meglio è)
  • se vuoi aggiungere un elemento, calcoli tutti gli khash di questo valore e imposti i bit corrispondenti a 1
  • se vuoi controllare se l'elemento esiste, calcoli anche tutti gli khash e se almeno uno di essi non è impostato, sicuramente non è nell'insieme. Altrimenti può essere nel set.

Anche questa descrizione è sufficiente per capire perché non possiamo esserne sicuri (puoi ottenere tutti i bit impostati da vari altri valori). Ecco una visualizzazione molto bella di come funziona .

inserisci qui la descrizione dell'immagine


Quindi quando possono essere utili i filtri bloom? La risposta breve è ovunque in cui i falsi positivi sono accettabili e dove vorresti controllare se c'è qualcosa nel set , ma anche se non lo sono, può essere una prima linea di difesa escludere costose chiamate ai verificatori.

Ecco un elenco di descrizioni più concrete:

  • un esempio standard di siti Web dannosi e un browser è descritto in quasi tutti i luoghi in cui si parla di filtri bloom
  • èuna password debole: invece di avere un enorme set di tutte le possibili password deboli, puoi semplicemente controllare se la password non è sicuramente debole con un filtro bloom molto più piccolo
  • se disponi di un elenco di articoli e di un elenco di utenti, puoi utilizzare il filtro bloom per mostrare gli articoli degli utenti che non hanno letto. La cosa interessante è che puoi avere un solo filtro (controlla se c'è la combinazione di user_id + article_id)
  • bitcoin utilizza il filtro bloom per la sincronizzazione del portafoglio
  • I server Web di Akamai utilizzano filtri Bloom per impedire che "meraviglie uniche" vengano archiviate nelle cache del disco. Le meraviglie uniche sono gli oggetti web richiesti dagli utenti una sola volta, qualcosa che Akamai ha trovato applicato a quasi i tre quarti della loro infrastruttura di cache. L'utilizzo di un filtro Bloom per rilevare la seconda richiesta per un oggetto web e la memorizzazione nella cache di tale oggetto solo alla sua seconda richiesta impedisce a meraviglie one-hit di entrare nella cache del disco, riducendo in modo significativo il carico di lavoro del disco e aumentando i tassi di hit della cache del disco (presi da esempi nel filtro di bloom articolo su wiki)

13

I filtri Bloom sono molto utili nella bioinformatica. Possono essere più efficienti in termini di spazio rispetto all'utilizzo di un hash normale, specialmente quando la dimensione delle stringhe con cui stai lavorando può essere di centinaia di milioni di lettere con un alfabeto molto piccolo, ad esempio {A, G, T, C}. Di solito vengono utilizzati per valutare se un certo k-mer è presente o assente in un genoma. C'è un esempio di uno usato per qualcosa di rilevante qui .

MODIFICARE:

Le molteplici funzioni hash vengono utilizzate per ridurre al minimo i falsi positivi. La speranza è che tra tutte le funzioni k-hash ogni valore abbia una firma univoca nell'array di bit rispetto a ogni altro valore possibile. Tuttavia, esistono falsi positivi, ma possono essere ridotti al minimo a un livello gestibile. Usando questa tecnica si hash elementi indipendentemente dalla loro dimensione. Quando li cerchi, usi ciascuna funzione hash e controlli per assicurarti che i loro valori di bit siano tutti 1.

Confronta questo con il genoma umano, dove un aumento della dimensione dell'elemento aumenta significativamente la dimensione della tabella hash (la dimensione della tabella è 4 * 4 k ). Questo presuppone che codifichi gli elementi usando 2 bit / lettera.


1
Scusa, forse sto fraintendendo, ma come possono essere più efficienti in termini di spazio rispetto a un normale hash? L'hash di una stringa è un output di lunghezza fissa e si imposta semplicemente quel valore su 0 o 1. Questo è anche ciò che farebbero i filtri bloom, ma i filtri bloom lo farebbero su più funzioni hash. Dove sto fraintendendo?
mal di testa

Non è molto utile memorizzare solo un singolo hash. Quindi non avrebbe modo di gestire le collisioni di hash. La maggior parte delle implementazioni di tabelle hash hanno un modo di affrontare questo problema che comporta un sovraccarico. I dizionari Python, ad esempio, memorizzano la chiave insieme all'hash e iniziano a sondare linearmente in caso di collisione. Il filtro bloom lo elimina e cerca di ridurre al minimo il danno inerente a farlo utilizzando più hash.
Bret Fontecchio

1
Perché non creare un filtro bloom ma con una sola funzione hash? forse funzione hash "relativamente grande". Ma uno invece di tanti
giorgim

7

Se un filtro Bloom restituisce che un elemento è membro dell'insieme, esiste una certa probabilità di un falso positivo. Se solo una singola funzione hash fosse utilizzata per indicare l'appartenenza all'insieme, la probabilità di un falso positivo sarebbe maggiore rispetto all'utilizzo di più funzioni hash.


Serve una seria elaborazione sulla carne della risposta: " la probabilità di un falso positivo sarebbe maggiore rispetto all'utilizzo di più funzioni di hash " ...
Pacerier
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.