2010-11-18 2 views
6

J'ai une énorme liste de séquences multi-octets (appelons les mots) que j'ai besoin de stocker dans un fichier et que je dois pouvoir rechercher rapidement. D'énormes moyens: Environ 2 millions de ceux-ci, chacun 10-20 octets de longueur.Compression et recherche d'une énorme liste de mots

En outre, chaque mot doit avoir une valeur d'étiquette associée, afin que je puisse utiliser pour référencer plus de données (externe) pour chaque élément (par conséquent, le dictionnaire d'un correcteur orthographique ne fonctionne pas ici que seulement fournit une hit-test). Si c'était juste en mémoire, et si la mémoire était abondante, je pourrais simplement stocker tous les mots dans une carte hachée (alias dictionnaire, alias paires clé-valeur), ou dans une liste triée pour une recherche binaire.

Cependant, je voudrais compresser les données fortement, et préférerais également ne pas devoir lire les données dans la mémoire mais chercher plutôt à l'intérieur du dossier. Comme les mots sont principalement basés sur le langage anglais, il y a une certaine probabilité que certains "sillables" dans les mots se produisent plus souvent que d'autres - ce qui est probablement utile pour un algorithme efficace. Est-ce que quelqu'un peut me diriger vers une technique ou un algorithme efficace pour cela?

Ou même des exemples de code?

Mise à jour

Je figure que DAWG ou quoi que ce soit des routes similaires le chemin dans suffixes communs de cette façon ne fonctionnera pas pour moi, parce que je ne serai pas capable de marquer chaque chemin de mot complet avec une personne valeur. Si je devais détecter des suffixes communs, je devrais les mettre dans leur propre dictionnaire (table de recherche) de sorte qu'un nœud puisse les référencer, mais le nœud garderait son propre nœud de fin pour stocker la valeur de balise de ce chemin.

En fait, c'est probablement la voie à suivre:

Au lieu de construire les nœuds d'arbres pour de simples caractères seulement, je pourrais essayer de trouver des séquences de caractères souvent utilisés, et faire un noeud pour ceux aussi bien. De cette façon, les nœuds uniques peuvent couvrir plusieurs caractères, ce qui peut conduire à une meilleure compression. Maintenant, si c'est viable, comment pourrais-je trouver des sous-séquences souvent utilisées dans toutes mes phrases? Avec environ 2 millions de phrases composées généralement de 1-3 mots, il sera difficile d'exécuter toutes les permutations de toutes les sous-chaînes possibles ...

+2

20 octets * 2 millions = 40Mb. C'est minuscule par rapport à la quantité typique de mémoire dans un ordinateur. Si vous les stockez dans un tableau trié, vous utiliserez la recherche binaire pour la recherche, et vous aurez à peine besoin de mémoire supplémentaire. – jkff

+0

Oui, 40mb c'est pas beaucoup. Et si c'est la vitesse qui vous préoccupe, gardez les données en mémoire aussi claires que possible. – ruslik

+0

Comme écrit ci-dessous, les 40 Mo doivent venir avec l'application, et j'aime garder la taille de téléchargement de l'application beaucoup plus petite. De plus, ce n'est pas la seule partie. Il y a une plus grande partie d'un autre ensemble de "mots", qui n'a pas besoin d'être interrogeable mais qui peut être compressé, car cela représentera environ 1GB dans les chaînes brutes. Une fois que j'ai trouvé un algo approprié pour ce qui précède, j'espère pouvoir l'utiliser sur cet autre, plus grand, aussi. –

Répondre

7

Il existe une structure de données appelée trie. Je crois que cette structure de données est parfaitement adaptée à vos besoins. Fondamentalement, un trie est un arbre où chaque nœud est une lettre et chaque nœud a des nœuds enfants.Dans une lettre basée sur trie, il y aurait 26 enfants par nœud.

Selon la langue que vous utilisez, il peut être plus facile ou mieux de stocker une liste de longueur variable lors de la création. Cette structure donne: a) Recherche rapide. Après un mot de longueur n, vous pouvez trouver la chaîne dans n liens dans l'arbre. b) Compression. Les préfixes communs sont stockés. Exemple: Le mot BANANA et BANAL auront tous les deux des nœuds B, A, N, A égaux, puis le dernier nœud (A) aura 2 enfants, L et N. Vos nœuds peuvent également stocker d'autres informations sur le mot .

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

Andrew JS

+0

J'avais l'intuition que ce serait la réponse. Bien que je n'ai jamais traité expressément, j'ai eu une idée que c'est ce à quoi cela ressemblerait. Pourtant, je me demande, pour gérer l'arbre, chaque nœud doit porter une liste de tous ses enfants. Dans un format de fichier compact ou de mémoire, cela signifierait que, à condition que l'arborescence dépasse 1 Mo, j'aurais besoin d'un pointeur de 32 bits plus la taille du nom de l'enfant (dans un arbre organisé par octets simples ce serait un octet) . Je me demande si cela ne conduira pas à une consommation excessive de mémoire en raison de ce ménage. –

+0

@Thomas - regardez la vidéo que j'ai postée. Il s'agit d'un fichier utilisé par un IA boggle qui contient un DAWG (similaire à un Trie mais plus sophistiqué). Vous n'avez pas besoin de 32 bits pour stocker le pointeur - vous pouvez être un peu plus intelligent (offsets et bitfields). –

0

Vous devriez vous familiariser avec le fichier indexé.

+0

Merci d'essayer d'aider, mais je pense que je connais bien le concept des fichiers indexés. J'ai appris que ca. 1982, je pense :) –

2

Je recommanderais d'utiliser un Trie ou un DAWG (graphe de mots acycliques dirigés). Il ya une grande conférence de Stanford sur faire exactement ce que vous voulez ici: http://academicearth.org/lectures/lexicon-case-study

+0

Merci pour le pointeur vidéo. Un peu allongé (je pourrais sauter beaucoup de bases), mais explique bien toutes les pensées de design qui le sous-tendent. Je pense aussi que le classique DAWG ne fonctionnera pas - j'ai ajouté des explications à mon article original à ce sujet. –

+0

Ajouter le lien mis à jour: https://see.stanford.edu/Course/CS106B/148 –

0

Avez-vous essayé d'utiliser une carte de hachage? La chose est, sur une architecture de système d'exploitation moderne, le système d'exploitation utilisera la mémoire virtuelle pour échanger les segments de mémoire inutilisés sur le disque de toute façon. Il se peut donc que le simple fait de tout charger dans une carte de hachage soit réellement efficace. Et comme le souligne jkff, votre liste ne serait que d'environ 40 Mo, ce qui n'est pas très important.

+0

40Mo est beaucoup si je dois l'inclure dans le téléchargement de mon application. Je m'attends à ce qu'il soit populaire :) –

+0

En outre, j'essaie de garder l'empreinte de la mémoire _on disk_ low. Une table de hachage ne sera pas utile là-bas. –

1

Jetez un oeil sur le papier "How to sqeeze a lexicon". Il explique comment construire un automate à états finis minimisé (qui est juste un autre nom pour un DAWG) avec un mappage un-à-un des mots aux nombres et vice versa. Exactement ce dont vous avez besoin.

+0

Merci, mais j'ai besoin d'un nœud de terminaison distinct pour chaque chemin. Voir mon post original (amélioré) pourquoi. –

+0

Avec le FSA de cet article, vous obtenez un nombre unique (et dense) pour chaque chemin. Vous pouvez utiliser ce numéro pour stocker les informations associées en externe, par ex. dans un tableau, dans une base de données ou dans un fichier avec une longueur d'enregistrement fixe. – hmuelner

Questions connexes