2010-11-18 8 views
6

Tengo una enorme lista de secuencias de varios bytes (vamos a llamarlas palabras) que necesito almacenar en un archivo y que necesito poder buscar rápidamente. Enorme significa: alrededor de 2 millones de esos, cada 10-20 bytes de longitud.Compresión y búsqueda de la enorme lista de palabras

Además, cada palabra tendrá una etiqueta valor asociado con ella, de modo que pueda utilizar eso para hacer referencia a más de datos (externa) de cada elemento (por lo tanto, el diccionario de un corrector ortográfico no funciona aquí como que sólo proporciona una hit-test).

Si esto fuera solo memoria, y si hubiera suficiente memoria, podría simplemente almacenar todas las palabras en un mapa hash (también conocido como diccionario, también conocido como pares clave-valor) o en una lista ordenada para una búsqueda binaria.

Sin embargo, me gustaría comprimir los datos altamente, y también preferiría no tener que leer los datos en la memoria, sino buscar dentro del archivo.

Como las palabras se basan principalmente en el idioma inglés, hay una cierta probabilidad de que ciertos "sillables" en las palabras aparezcan con mayor frecuencia que otros, lo que probablemente sea útil para un algoritmo eficiente.

¿Alguien me puede indicar una técnica o algoritmo eficiente para esto?

¿O incluso ejemplos de código?

actualización

Calculo que DAWG ni nada rutas similares en el camino sufijos comunes de esta manera no va a funcionar para mí, porque entonces no voy a ser capaz de etiquetar cada ruta completa palabra con un individuo valor. Si tuviera que detectar los sufijos comunes, tendría que ponerlos en su propio diccionario (tabla de búsqueda) para que un nodo trie pueda hacer referencia a ellos, pero el nodo mantendría su propio nodo final para almacenar el valor de la etiqueta de esa ruta.

De hecho, eso es probablemente el camino a seguir:

En lugar de construir los nodos del árbol de sólo caracteres individuales, que podrían tratar de encontrar secuencias de caracteres de uso frecuente, y hacer un nodo de esos también. De esta forma, los nodos individuales pueden cubrir múltiples caracteres, lo que puede conducir a una mejor compresión.

Ahora, si eso es viable, ¿cómo podría encontrar secuencias a menudo usadas en todas mis frases? Con aproximadamente 2 millones de frases que constan de 1 a 3 palabras, será difícil ejecutar todas las permutaciones de todas las subcadenas posibles ...

+2

20 bytes * 2 millones = 40Mb. Eso es minúsculo en comparación con la cantidad típica de memoria en una computadora. Si los almacena en una matriz ordenada, usará la búsqueda binaria para buscar, y apenas necesitará memoria adicional. – jkff

+0

Sí, 40mb no es mucho. Y si le preocupa la velocidad, mantenga los datos en la memoria lo más simple posible. – ruslik

+0

Como se indica a continuación, los 40 MB deben venir con la aplicación, y me gusta mantener el tamaño de descarga de la aplicación mucho más pequeño. Además, esa no es la única partición. Hay una porción más grande de otro conjunto de "palabras", que no necesita ser buscable pero aún compresible porque equivaldrá a alrededor de 1GB en cadenas sin formato. Una vez que encontré un algo adecuado para lo anterior, espero usarlo también en este otro conjunto más grande. –

Respuesta

7

Existe una estructura de datos llamada trie. Creo que esta estructura de datos se adapta perfectamente a sus necesidades. Básicamente, un trie es un árbol donde cada nodo es una letra y cada nodo tiene nodos secundarios.En un trie basado en letras, habría 26 hijos por nodo.

Según el idioma que utilice, puede ser más fácil o mejor almacenarlo como una lista de longitud variable durante la creación.

Esta estructura da: a) Búsqueda rápida. Siguiendo una palabra de longitud n, puede encontrar la cadena en n enlaces en el árbol. b) Compresión. Los prefijos comunes se almacenan.

Ejemplo: La palabra BANANA y BANAL ambos tendrán Nodos B, A, N, A iguales y luego el último (A) nodo tendrá 2 hijos, L y N. Sus Nodos también pueden almacenar otra información sobre la palabra .

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

Andrew JS

+0

Tenía la corazonada de que esta sería la respuesta. Aunque nunca he manejado un trie expresamente, tenía una idea de que así sería. Aún así, me pregunto, para administrar el árbol, cada nodo tiene que llevar una _list_ de todos sus hijos. En un archivo compacto o forma de memoria, esto significaría que, siempre que el árbol exceda 1 MB de tamaño, necesitaré un puntero de 32 bits más el tamaño del nombre del niño (en un árbol organizado por bytes individuales esto sería un byte) . Me pregunto si esto no conducirá a un consumo excesivo de memoria debido a este servicio de limpieza. –

+0

@Thomas - mira el video que publiqué. Se trata de un archivo utilizado por un boggle AI que contiene un DAWG (similar a un Trie pero más sofisticado). No necesita 32 bits para almacenar el puntero; puede ser un poco más inteligente (desplazamientos y campos de bits). –

0

Debe familiarizarse con el archivo indexado.

+0

Gracias por intentar ayudar, pero creo que estoy familiarizado con el concepto de archivos indexados. Aprendí que ca. 1982, creo :) –

2

Recomendaría usar un Trie o un DAWG (gráfico de palabras acíclica dirigido). Hay una gran conferencia de Stanford sobre cómo hacer exactamente lo que quiere aquí: http://academicearth.org/lectures/lexicon-case-study

+0

Gracias por el puntero de video. Un poco largo (podría omitir muchos de los conceptos básicos), pero explica bien todos los pensamientos de diseño detrás de él. También me imagino que el clásico DAWG no funcionará. He agregado explicaciones a mi publicación original sobre eso. –

+0

Agregando el enlace actualizado: https://see.stanford.edu/Course/CS106B/148 –

0

¿Ha intentado simplemente usar un mapa hash? La cosa es que, en una arquitectura de sistema operativo moderna, el sistema operativo usará memoria virtual para intercambiar segmentos de memoria no utilizados en el disco de todos modos. Por lo tanto, puede resultar que solo cargarlo todo en un mapa hash sea realmente eficiente.

Y como jkff señala, su lista solo sería de unos 40 MB, que no es mucho.

+0

40MB es mucho si tengo que incluirlo en la descarga de mi aplicación. Espero que sea popular :) –

+0

Además, intento mantener la huella de memoria _en disco_ baja. Una tabla hash no será de ayuda allí. –

1

Tenga una mirada en el papel "How to sqeeze a lexicon". Explica cómo construir un autómata de estado finito minimizado (que es solo otro nombre para un DAWG) con un mapeo uno a uno de palabras a números y viceversa. Exactamente lo que necesitas

+0

Gracias, pero necesito un nodo final distinto para cada ruta. Ver mi publicación original (mejorada) por qué. –

+0

Con la FSA en este documento usted obtiene un número único (y denso) para cada ruta. Aou puede usar este número para almacenar información asociada externamente, p. en una matriz, en una base de datos o en un archivo con una longitud de registro fija. – hmuelner

Cuestiones relacionadas