2010-02-08 12 views
24

sto lavorando con un ampio set (5-20 milioni di euro) di chiavi String (durata media 10 caratteri) che ho bisogno di memorizzare in un a struttura di dati di memoria che supporta la seguente operazione in tempo costante o quasi in tempo costante:bisogno di memoria modo efficiente per archiviare tonnellate di stringhe (era: implementazione HAT-Trie in java)

// Returns true if the input is present in the container, false otherwise 
public boolean contains(String input) 

hashmap di Java sta dimostrando di essere più che soddisfacente per quanto riguarda il throughput è interessato, ma sta prendendo un sacco di memoria. Sto cercando una soluzione che sia efficiente in termini di memoria e supporti ancora un throughput che sia accettabile (paragonabile o quasi all'altezza dell'hashing).

Non mi importa dei tempi di inserimento/cancellazione. Nella mia applicazione, eseguirò solo gli inserimenti (solo al momento dell'avvio) e successivamente eseguirò una query sulla struttura dei dati solo utilizzando il metodo contains per la durata dell'applicazione.

Ho letto che la struttura dati HAT-Trie è la più vicina alle mie esigenze. Mi chiedo se esiste una libreria che ha un'implementazione.

Altri suggerimenti con indicazioni per implementazioni benvenute.

Grazie.

+2

Suppongo che ogni altra infrastruttura utilizzerà molta memoria, se implementata in Java. – ebo

+1

@ebo Non se l'implementazione sottostante utilizza gli array chars/char. Non è necessario mantenere l'oggetto String di input. In generale, è necessario utilizzare una memoria inferiore. – hashable

+0

Domanda molto interessante. –

risposta

12

Il trie sembra un'ottima idea per i vostri limiti.

A "pensare fuori dagli schemi" alternativo:

se lo può permettere una certa probabilità di rispondere "presente" per una stringa che è assente

EDIT: se lo può permettere falsi positivi, utilizzare un Bloom filter come suggerito da WizardOfOdds nei commenti.

Per k = 1, un filtro Bloom è come una tabella hash senza le chiavi: ogni "bucket" è semplicemente un valore booleano che indica se almeno un input con lo stesso hash era presente. Se i falsi positivi dell'1% sono accettabili, la tabella hash può essere piccola come circa 100 * 20 milioni di bit o circa 200 MiB. Per 1 su 1000 falsi positivi, 2GiB.

L'utilizzo di diverse funzioni di hash anziché di uno può migliorare il tasso di falsi positivi per la stessa quantità di bit.

+3

@Pascaul Cuoq: Non sto facendo downvoting ma stai reinventando una ruota qui, probabilmente meno efficiente di quello che esiste. Non so da dove prendi i tuoi numeri, ma esiste una struttura dati nota che consente una percentuale di falsi positivi, si chiama "Bloom Filter". Un filtro di fioritura per 200 milioni di voci con un falso positivo accettabile all'1% richiederebbe 154 MB. – SyntaxT3rr0r

+0

In realtà, 23 MB per 20 milioni di voci come specificato nel poster originale. Ma ovviamente non ci è stato detto che i falsi positivi sono OK ... –

+0

@WizardOfOdds Grazie per il puntatore. Stavo suggerendo è davvero un filtro di fioritura ingenuo (k = 1). –

2

Per l'efficienza dello spazio, ricerca O (log (n)) e codice semplice, provare la ricerca binaria su una matrice di caratteri. 20 milioni di chiavi di lunghezza media 10 rendono 200 milioni di caratteri: 400 MB se hai bisogno di 2 byte/carattere; 200 MB se riesci a farla franca 1. In cima a questo devi in ​​qualche modo rappresentare i confini tra i tasti dell'array. Se puoi prenotare un carattere separatore, questo è un modo; altrimenti potresti usare un array parallelo di offset int.

La variante più semplice utilizza una serie di stringhe, a un costo di spazio elevato dall'overhead per oggetto. Dovrebbe ancora battere un hashtable nell'efficienza dello spazio, anche se non altrettanto.

+0

@Darius Bacon: interi dizionari che utilizzano la ricerca O (log n) possono essere memorizzati utilizzando meno di 10 bit per stringa (!!!). Veramente. Meno di 10 bit, l'ho fatto. Esistono anche algoritmi di compressione elevati per dizionari che utilizzano 12 bit per parola che consentono anche una rapida ricerca dei suggerimenti. Ma la domanda originale posta esplicitamente su una O (1) contiene, non una O (log n), quindi non posso suggerire una tale tipologia di struttura dei dati "alta compressione, 10 bit per parola" come risposta. – SyntaxT3rr0r

+1

Sì, ho indicato dizionari così compressi nella mia risposta ad un'altra domanda. Non proverei nulla di così carino come il mio primo suggerimento qui - ci vorrebbe un lavoro considerevole per renderlo più veloce, se può essere fatto del tutto, non è vero? E la domanda chiedeva * vicino * tempo costante; se questo è abbastanza vicino dovrà essere all'altezza del poster originale. –

+0

(Questo scenario di un hash in cui i limiti di memoria sono cambiati nella ricerca binaria si è già verificato nella mia vita lavorativa, in realtà. Il programmatore più giovane che si è imbattuto in questo problema stava progettando una soluzione complessa, ma la ricerca binaria funzionava bene Per inciso, ho introdotto i filtri Bloom in un'altra parte dello stesso progetto ... è come se fosse tutto preparato per commentare questo problema di stackoverflow qui.) –

4

Google visualizza un post sul blog HAT tries in Java. Ma non vedo come questo risolverà il problema direttamente: la struttura è un trie superficiale rispetto ai prefissi dei tasti, con le foglie che sono hashtables che contengono i suffissi di tutte le chiavi con il prefisso specificato. Quindi, in totale, hai un sacco di hashtables che memorizzano tutte le chiavi che sono nel tuo attuale hashtable (magari salvando alcuni byte per chiave in generale a causa dei prefissi comuni). Ad ogni modo, hai bisogno di un hash più efficiente in termini di spazio rispetto a quello predefinito di Java, o il sovraccarico per oggetto ti colpirà altrettanto male.Quindi, perché non iniziare con una classe hashtable specializzata solo per le chiavi stringa, se segui questa strada e ti preoccupi della parte trie solo se sembra ancora utile?

2

Simile a un trie è un albero di ricerca ternario, ma un albero di ricerca ternario ha il vantaggio di utilizzare meno memoria. È possibile leggere sugli alberi di ricerca ternaria here, here e here. Anche uno dei principali articoli sull'argomento di Jon Bentley e Robert Sedgewick è here. Parla anche di ordinare le stringhe rapidamente, quindi non lasciatevi scoraggiare da quello.

+0

"Gli alberi ternari sono notevolmente più grandi delle mappe hash o della maggior parte dei disegni di alberi binari" (http: //abc.se/~re/code/tst/tst_docs/perf_notes.html) – ArtemGr

Problemi correlati