2010-11-18 19 views
6

Ho una lista enorme di sequenze multi-byte (chiamiamole parole) che ho bisogno di memorizzare in un file e che devo essere in grado di cercare rapidamente. Mezzi enormi: circa 2 milioni di quelli, ogni 10-20 byte di lunghezza.Compressione e ricerca di un enorme elenco di parole

Inoltre, ogni parola deve avere un tag valore associato con esso, in modo che possa utilizzare che per fare riferimento più dati (esterna) per ogni elemento (quindi, dizionario del controllo ortografico non funziona qui che fornisce solo hit-test).

Se questo fosse solo nella memoria, e se la memoria fosse un sacco, ho potuto semplicemente memorizzare tutte le parole in una mappa hash (aka dizionario, alias coppie chiave-valore), o in una lista ordinata per una ricerca binaria.

Tuttavia, mi piacerebbe comprimere i dati molto, e preferirei anche non dover leggere i dati in memoria, ma piuttosto cercare all'interno del file.

Poiché le parole si basano principalmente sulla lingua inglese, c'è una certa probabilità che alcuni "sillable" nelle parole si presentino più spesso di altri - il che è probabilmente utile per un algoritmo efficiente.

Qualcuno può indicarmi una tecnica efficiente o un algoritmo per questo?

O anche esempi di codice?

Aggiornamento

Ho capito che DAWG o niente percorsi simili il percorso nella suffissi comuni in questo modo non funziona per me, perché allora non sarò in grado di etichettare ogni percorso parola completa con un individuo valore. Se dovessi rilevare i suffissi comuni, dovrei inserirli nel loro dizionario (tabella di ricerca) in modo che un trie node possa farvi riferimento, tuttavia il nodo manterrebbe il proprio nodo finale per memorizzare il valore del tag di quel percorso.

In realtà, che è probabilmente la strada da percorrere:

Invece di costruire i nodi della struttura per soli singoli caratteri, potrei cercare di trovare sequenze di caratteri utilizzati più spesso, e fare un nodo per quelli pure. In questo modo, i singoli nodi possono coprire più caratteri, forse portando a una compressione migliore.

Ora, se ciò è fattibile, come troverei effettivamente sotto-sequenze spesso utilizzate in tutte le mie frasi? Con circa 2 milioni di frasi composte di solito 1-3 parole, sarà difficile eseguire tutte le permutazioni di tutte le sottostringhe possibili ...

+2

20 byte * 2 milioni = 40 MB. Questo è minuscolo rispetto alla tipica quantità di memoria in un computer. Se li si archivia in una matrice ordinata, si utilizzerà la ricerca binaria per la ricerca e difficilmente sarà necessaria alcuna memoria aggiuntiva. – jkff

+0

Sì, 40 MB non è molto. E se è la velocità che ti preoccupa, allora tieni i dati in memoria il più semplice possibile. – ruslik

+0

Come scritto di seguito, i 40 MB devono venire con l'app, e mi piace mantenere la dimensione del download dell'app molto più piccola. Inoltre, non è l'unica parzialità. C'è una porzione più ampia di un altro set di "parole", che non ha bisogno di essere ricercabile ma comunque comprimibile perché ammonterà a circa 1 GB nelle stringhe non elaborate. Una volta trovato un algo adatto a quanto sopra, spero di usarlo anche su quest'altro, più grande, insieme. –

risposta

7

Esiste una struttura dati chiamata trie. Credo che questa struttura dati sia perfettamente adatta alle tue esigenze. Fondamentalmente un trie è un albero in cui ogni nodo è una lettera e ogni nodo ha nodi figli.In un trie basato su lettere, ci sarebbero 26 bambini per nodo.

A seconda della lingua utilizzata, potrebbe essere più facile o meglio archiviare come lista di lunghezza variabile durante la creazione.

Questa struttura fornisce: a) Ricerca rapida. Seguendo una parola di lunghezza n, puoi trovare la stringa in n link nell'albero. b) Compressione. I prefissi comuni sono memorizzati.

Esempio: la parola BANANA e BANAL avranno entrambi i nodi B, A, N, A uguali e quindi l'ultimo nodo (A) avrà 2 figli, L e N. I tuoi nodi possono anche memorizzare altre informazioni sulla parola .

(http://en.wikipedia.org/wiki/Trie)

Andrew JS

+0

Ho avuto la sensazione che questa sarebbe stata la risposta. Mentre non ho mai gestito un trie espressamente, ho avuto l'idea che questo è come sarebbe. Tuttavia, mi chiedo, per gestire l'albero, ogni nodo deve portare una lista di tutti i suoi figli. In un file compatto o in una memoria, ciò significherebbe che, a condizione che l'albero superi 1 MB di dimensione, avrò bisogno di un puntatore a 32 bit più la dimensione del nome del bambino (in un albero organizzato da singoli byte questo sarebbe un byte) . Mi chiedo se questo non porterà a un consumo eccessivo di memoria a causa di questo servizio di pulizia. –

+0

@Thomas - guarda il video che ho postato. Si tratta di un file utilizzato da un AI boggle che contiene un DAWG (simile a un Trie ma più sofisticato). Non hai bisogno di 32 bit per memorizzare il puntatore - puoi essere un po 'più intelligente (offset e bitfield). –

0

È necessario acquisire familiarità con il file indicizzato.

+0

Grazie per aver cercato di aiutare, ma penso di conoscere bene il concetto di file indicizzati. Ho imparato che ca. 1982, penso :) –

2

Si consiglia di utilizzare un Trie o un DAWG (grafico di parola aciclica diretto). C'è una grande conferenza di Stanford sul fare esattamente quello che vuoi qui: http://academicearth.org/lectures/lexicon-case-study

+0

Grazie per il puntatore del video. Un po 'allungato (potrei saltare un sacco di nozioni di base), ma spiega bene tutti i pensieri di progettazione che ci sono dietro. Immagino anche che la classica DAWG non funzioni - ho aggiunto spiegazioni al mio post originale su questo. –

+0

Aggiunta del collegamento aggiornato: https://see.stanford.edu/Course/CS106B/148 –

0

Hai provato ad usare una mappa di hash? Il fatto è che, su una moderna architettura del sistema operativo, il sistema operativo utilizzerà la memoria virtuale per scambiare comunque segmenti di memoria non utilizzati su disco. Quindi potrebbe risultare che il solo caricamento di tutto in una mappa di hash sia effettivamente efficiente.

E come sottolinea jkff, la tua lista sarebbe solo di circa 40 MB, che non è poi così tanto.

+0

40 MB è molto se devo includerlo nel download della mia app. Mi aspetto che sia popolare :) –

+0

Inoltre, cerco di mantenere l'ingombro della memoria su disk_ basso. Una tabella hash non sarà di aiuto lì. –

1

Dai un'occhiata alla carta "How to sqeeze a lexicon". Spiega come costruire un automa a stati finiti minimizzato (che è solo un altro nome per un DAWG) con una mappatura uno-a-uno delle parole ai numeri e viceversa. Esattamente quello di cui hai bisogno.

+0

Grazie, ma ho bisogno di un nodo finale distinto per ogni percorso. Vedi il mio post originale (migliorato) perché. –

+0

Con la FSA in questo documento si ottiene un numero univoco (e denso) per ogni percorso. È possibile utilizzare questo numero per archiviare le informazioni associate esternamente, ad es. in un array, in un database o in un file con lunghezza di record fissa. – hmuelner

Problemi correlati