Pregunta

editar: muchas gracias por todas las respuestas. Aquí están los resultados después de aplicar las optimizaciones hasta el momento:

  • Cambiando a la clasificación de caracteres y longitud de ejecución - nuevo tamaño de base de datos 42M
  • Eliminando los índices en los valores booleanos - nuevo tamaño DB 33M

La parte realmente interesante es que no ha requerido ningún cambio en el código del iPhone

Tengo una aplicación para iPhone con un gran diccionario en formato sqlite (solo lectura). Estoy buscando ideas para reducir el tamaño del archivo DB, que actualmente es muy grande.

Aquí está el número de entradas y el tamaño resultante de la base de datos sqlite:

franks-macbook:DictionaryMaker frank$ ls -lh dictionary.db
-rw-r--r--  1 frank  staff    59M  8 Oct 23:08 dictionary.db
franks-macbook:DictionaryMaker frank$ wc -l dictionary.txt
  453154 dictionary.txt

... un promedio de aproximadamente 135 bytes por entrada.

Aquí está mi esquema de base de datos:

create table words (word text primary key, sowpods boolean, twl boolean, signature text)
create index sowpods_idx on words(sowpods)
create index twl_idx on words(twl)
create index signature_idx on words(signature)

Aquí hay algunos datos de muestra:

photoengrave|1|1|10002011000001210101010000
photoengraved|1|1|10012011000001210101010000
photoengraver|1|1|10002011000001210201010000
photoengravers|1|1|10002011000001210211010000
photoengraves|1|1|10002011000001210111010000
photoengraving|1|1|10001021100002210101010000

El último campo representa las frecuencias de letras para la recuperación de anagramas (cada posición está en el rango de 0..9). Los dos booleanos representan sub diccionarios.

Necesito hacer consultas como:

select signature from words where word = 'foo'
select word from words where signature = '10001021100002210101010000' order by word asc
select word from words where word like 'foo' order by word asc
select word from words where word = 'foo' and (sowpods='1' or twl='1')

Una idea que tengo es codificar las frecuencias de las letras de manera más eficiente, por ejemplo, binario codifíquelos como un blob (tal vez con RLE ya que hay muchos ceros?). ¿Alguna idea sobre la mejor manera de lograr esto, u otras ideas para reducir el tamaño? Estoy construyendo el DB en ruby, y lo leo en el teléfono en el objetivo C.

¿También hay alguna forma de obtener estadísticas en la base de datos para que pueda ver qué es lo que más espacio usa?

¿Fue útil?

Solución

No tengo claro todos los casos de uso para el campo de firma, pero parece que sería beneficioso almacenar una versión alfabetizada de la palabra.

Otros consejos

¿Has intentado escribir el " vacío " comando para asegurarse de que no tiene espacio extra en la base de datos que olvidó recuperar?

Elimine los índices en sowpods y twl; es probable que no ayuden a los tiempos de consulta y definitivamente están ocupando mucho espacio.

Puede obtener estadísticas de la base de datos utilizando sqlite3_analyzer de la página de descargas de SQLite .

Como un enfoque totalmente diferente, puede intentar usar un filtro de floración en lugar de un completo base de datos. Básicamente, un filtro de floración consiste en un grupo de funciones hash, cada una de las cuales está asociada con un campo de bits. Para cada palabra legal, se evalúa cada función hash y se establece el bit correspondiente en el campo de bit correspondiente. El inconveniente es que teóricamente es posible obtener falsos positivos, pero se pueden minimizar / eliminar prácticamente con suficientes hashes. El lado positivo es un gran ahorro de espacio.

El creador de SQLite vende una versión de SQLite que incluye compresión de base de datos (y cifrado). Esto sería perfecto.

Su mejor apuesta es usar la compresión, que desafortunadamente SQLite no es compatible de forma nativa en este momento. Afortunadamente, alguien se tomó el tiempo de desarrollar una extensión de compresión para eso, lo que podría ser lo que necesites.

De lo contrario, recomendaría almacenar sus datos principalmente en formato comprimido y descomprimir sobre la marcha.

Como campo de texto, signature actualmente utiliza al menos 26 * 8 bytes por entrada (208 bytes), pero si tuviera que empaquetar los datos en un campo de bits, probablemente podría salirse con la suya. 3 bits por letra (reduciendo su frecuencia máxima por letra a 7). Eso significaría que podría empaquetar la firma completa en 26 * 3 bits = 78 bits = 10 bytes. Incluso si usara 4 bits por letra (para una frecuencia máxima de 15 por letra) solo usaría 104 bits (13 bytes).

EDITAR: Después de pensar un poco más, creo que 4 bits por letra (en lugar de 3) sería una mejor idea porque haría las matemáticas binarias más fáciles.

EDIT2: leyendo los documentos en tipos de datos SQLite , parece que puede ser capaz de hacer simplemente la " firma " el campo abarca 26 columnas del tipo INTEGER y SQLite hará lo correcto y solo usará tantos bits como sea necesario para almacenar el valor.

¿Considero correctamente que tiene aproximadamente 450 mil palabras como esa en su base de datos?

No tengo ni idea sobre el iPhone, ni en serio sobre sqlitem pero ... siempre que sqlite no permita una manera de guardar el archivo como gz de inmediato (tal vez ya lo haga internamente. no, no parece así cuando dices que es alrededor de 135 b por entrada (ni siquiera con ambos índices), me alejaría del enfoque de la tabla, lo guardaría " manualmente " en un compresión de aproximación del diccionario y cree el resto sobre la marcha y en la memoria. Eso debería funcionar MUY bien en su tipo de datos.

Espere ... ¿Está utilizando esa firma para permitir la búsqueda de textos completos o el reconocimiento erróneo? ¿La búsqueda de texto completo en sqlite no hará obsoleto ese campo?

Como se anotó en el almacenamiento " Firma " Más eficientemente parece una buena idea.

Sin embargo, también parece que podría obtener una tonelada de ahorro de espacio al utilizar algún tipo de tabla de búsqueda de palabras, ya que parece que está tomando una palabra raíz y luego agregando " er " ;, " ed " ;, ". ; es " ;, etc. ¿por qué no tener una columna con un ID numérico que haga referencia a una palabra raíz de una tabla de búsqueda separada, y luego una columna separada con un ID numérico que haga referencia a una tabla de sufijos de palabras comunes que se agregarían a la palabra base? .

Si hubiera algún truco para almacenar versiones abreviadas de firmas para varias entradas con una sola palabra raíz, también podría emplearlas para reducir el tamaño de las firmas almacenadas (no estoy seguro de qué algoritmo produce esos valores)

Esto también parece tener mucho sentido para mí, ya que tiene la palabra " palabra " columna como clave principal, pero ni siquiera la indexe, solo cree una columna numérica que sea la ID principal de la tabla.

mhmm ... un iPhone ... ¿no tiene una conexión de datos permanente? Creo que aquí es donde una aplicación web / servicio web puede saltar cómodamente. Mueva la mayor parte de su lógica empresarial al servidor web (tendrá un SQL real con FTS y mucha memoria) y obtenga esa información en línea para el cliente en el dispositivo.

Como se mencionó en otra parte, pierda los índices en las columnas booleanas, casi con seguridad serán más lentos (si se usan) que un escaneo de tablas y van a usar el espacio innecesariamente.

Consideraría aplicar una compresión simple a las palabras, codificación Huffman es bastante buena para este tipo de cosas. Además, observaría las firmas: ordene las columnas en orden de frecuencia de letras y no se moleste en almacenar los ceros finales, lo que puede estar implícito. Supongo que también podrías codificarlos con Huffman.

Siempre asumiendo que las cadenas codificadas no alteran a SQLite, por supuesto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top