J'espérais faire un petit remue-méninges sur le sujet du stockage des données à n programmes . Dans mon projet, j'essaie de résoudre des problèmes linguistiques où je connais tous les éléments de données ( n -1) et je veux deviner statistiquement mon n en utilisant une interpolation linéaire sur tous les n -grammes applicables . (Oui, il existe un tagueur qui attribue des balises à des mots connus en fonction de son lexique et un arbre de suffixes qui essaie de deviner le type de mot pour les mots inconnus; le composant à n- grammes discuté ici sera chargé de résoudre l'ambiguïté.)
Mon approche initiale serait de simplement stocker tous les n- grammes observés (pour n = 1..3, c'est-à-dire monogramme, bigramme, trigramme) dans des bases de données SQL respectives et de l'appeler un jour. Mais les exigences de mon projet peuvent changer pour inclure d'autres longueurs de vecteur ( n ), et je voudrais que mon application s'adapte à 4 grammes sans beaucoup de travail (mise à jour du schéma, mise à jour du code d'application, etc.); idéalement, je dirais simplement à mon application de travailler avec 4 grammes maintenant sans avoir à changer beaucoup (ou pas du tout) de code et à former ses données à partir d'une source de données donnée.
Pour résumer toutes les exigences:
- Possibilité de stocker n données -gram (initialement pour n = {1, 2, 3}
- Possibilité de changer les types de n -grammes à utiliser (entre les exécutions d'application)
- Capacité à (re) former les données de n-programmes (entre les exécutions d'application)
Possibilité d'interroger le magasin de données (par exemple, si j'ai observé A, B, C, j'aimerais connaître l'élément le plus fréquemment observé pour ce qui pourrait suivre en utilisant mes ensembles de données formés de 4, 3, 2, 1 gramme )
L'application sera probablement lourde en lecture, les ensembles de données ne seront probablement pas recyclés aussi souvent
- La solution utilise le .NET Framework (jusqu'à 4.0)
Maintenant, quelle conception conviendrait le mieux à une telle tâche?
- Une table fixe gérée par un serveur SQL (MSSQL, MySQL, ...) pour chaque n (ex. Tables dédiées aux bi-grammes, tri-grammes, etc.)
- Ou une solution de base de données de documents NoSQL qui stocke le premier n -1 comme la clé du document et le document lui - même contient la n valeur -ème et les fréquences observées?
- Ou quelque chose de différent?
la source
Réponses:
Étant donné que vous ne connaissez pas la plage optimale de N, vous voulez certainement pouvoir la changer. Par exemple, si votre application prédit la probabilité qu'un certain texte soit anglais, vous voudrez probablement utiliser des caractères N-grammes pour N 3..5. (C'est ce que nous avons découvert expérimentalement.)
Vous n'avez pas partagé les détails de votre application, mais le problème est suffisamment clair. Vous souhaitez représenter des données N-gramme dans une base de données relationnelle (ou une solution basée sur des documents NoSQL). Avant de suggérer ma propre solution, vous voudrez peut-être examiner les approches suivantes:
Maintenant, n'ayant lu aucun des liens ci-dessus, je suggère une approche de base de données relationnelle simple utilisant plusieurs tables, une pour chaque taille de N-gramme. Vous pouvez mettre toutes les données dans une seule table avec le maximum de colonnes nécessaires (c'est-à-dire stocker les bigrammes et les trigrammes dans ngram_4, en laissant les dernières colonnes nulles), mais je recommande de partitionner les données. Selon votre moteur de base de données, une seule table avec un grand nombre de lignes peut avoir un impact négatif sur les performances.
Ensuite, je vais vous donner une requête qui retournera le mot suivant le plus probable étant donné toutes vos tables de ngram. Mais d'abord, voici quelques exemples de données que vous devez insérer dans les tableaux ci-dessus:
Pour interroger le mot suivant le plus probable, vous utiliseriez une requête comme celle-ci.
Si vous ajoutez d'autres tables ngram, vous devrez ajouter une autre clause UNION à la requête ci-dessus. Vous remarquerez peut-être que dans la première requête, j'ai utilisé word1 = @ word3. Et dans la deuxième requête, mot1 = @ mot2 ET mot2 = @ mot3. C'est parce que nous devons aligner les trois mots de la requête pour les données ngram. Si nous voulons le mot suivant le plus probable pour une séquence de trois mots, nous devons comparer le premier mot des données bigrammes avec le dernier mot des mots de la séquence.
Vous pouvez modifier les paramètres de poids comme vous le souhaitez. Dans cet exemple, j'ai supposé que des grammes "n" ordinaux supérieurs seraient plus fiables.
PS Je structurerais le code du programme pour gérer n'importe quel nombre de tables ngram_N via la configuration. Vous pouvez modifier le programme de manière déclarative pour utiliser la plage N-grammes N (1..6) après avoir créé les tables ngram_5 et ngram_6.
la source
ngram_2
, l'expressionbuilding with
a freq est 0,5. Même question avec@bigramWeight
, qu'est-ce que c'est?. Je pense que freq est le champ sera mis à jour chaque fois que nous mettons à jour la base de données. C'est-à-dire si l'utilisateur saisit plus de chaîne, la fréquence de cette chaîne sera recalculée? 0,5 correspond à 0,5% du temps total utilisé ou du taux d'apparition de chaque phrase?Contrairement à ce que les autres suggèrent, je suggérerais d'éviter toute structure de données plus complexe qu'une table de hachage ou un magasin de valeurs-clés.
Gardez à l'esprit vos exigences d'accès aux données: a) 99% de requêtes - interrogez le ngram "aaa-bbb-ccc" et récupérez la valeur (ou 0) b) 1% de requêtes - insérer / mettre à jour un décompte de ngram spécifiques c) il n'y a pas (c).
Le moyen le plus efficace consiste à le récupérer avec une seule recherche. Vous pouvez utiliser un séparateur hors limites (ou échappé) pour combiner le n-gramme complet dans une seule chaîne (par exemple, "alpha | beta | gamma" pour 3 grammes, "alpha" pour unigram, etc.) et simplement le récupérer ( par le hachage de cela). C'est ainsi que beaucoup de logiciels NLP le font.
Si vos données de ngram sont petites (disons <1 Go) et tiennent dans la mémoire, je suggère d'utiliser une structure de mémoire en programme efficace (hashmaps, arbres, essais, etc.) pour éviter les frais généraux; et juste sérialiser / désérialiser en fichiers plats. Si vos données ngram sont de plusieurs téraoctets, vous pouvez choisir des magasins de valeurs-clés NoSQL répartis sur plusieurs nœuds.
Pour des performances supplémentaires, vous voudrez peut-être remplacer tous les mots partout avec des identifiants entiers afin que votre algorithme de base ne voie aucune chaîne (lente); il est alors légèrement différent de mettre en œuvre la même idée.
la source
Pas le plus efficace, mais simple et intégré à la base de données comme vous le souhaitez:
wordpos devrait avoir des index sur le document et pos.
les bigrammes sont:
Ensuite, vous pouvez compter () et grouper votre chemin vers des fréquences et d'autres choses.
Pour passer aux trigrammes, il suffit de générer cette chaîne pour inclure un mot3.
J'ai déjà fait cela auparavant (même si le SQL là-haut est probablement un peu rouillé). Je me suis installé sur un ensemble de fichiers plats qui pourraient être recherchés facilement puis diffusés sur le disque. Cela dépend un peu de votre matériel pour mieux le faire.
la source
En essayant d'améliorer les recherches simples de mes applications vers des bigrammes et des trigrammes à partir d'unigrammes, j'ai essentiellement vu votre question.
Si l'une des exigences est la capacité d'interroger un système de fichiers ou une base de données distribuée, cela pourrait également être intéressant pour vous: le document Pibiri et Venturini 2018 «Gérer efficacement les ensembles de données massifs de N-Gram» décrit un moyen efficace de stocker des données de n-grammes dans termes d'exécution et d'espace. Ils ont proposé leur mise en œuvre sur https://github.com/jermp/tongrams
Chaque "n" de n-grammes est conservé dans une table séparée accessible par une fonction de hachage parfaite minimale avec des capacités de sélection et de requête très rapides. Les tableaux sont statiques et construits par le code principal en utilisant une entrée au format de fichiers texte Google n-grammes.
Je n'ai pas encore utilisé le code, mais il existe de nombreuses façons avec vos exigences ouvertes d'où proviennent vos requêtes.
Une façon: si l'équivalent .NET d'un servlet est utilisé avec une base de données ou une banque de données, et si vous devez économiser de l'espace de stockage, le stockage de chaque table ngram sous forme binaire dans la base de données / banque de données en tant que table est une option (une base de données / table de banque de données pour le fichier statique résultant du code ngram efficace pour tous les 1 grammes, un autre pour tous les 2 grammes, etc.). Les requêtes seraient exécutées en invoquant le code n-gram efficace (encapsulé pour être accessible par votre servlet). C'est une solution de contournement pour créer une base de données distribuée qui utilise le code n-gram efficace pour accéder aux fichiers sur un système de fichiers distribué. Notez que les tables de base de données / banque de données binaires ont chacune la restriction de taille de fichier du système de fichiers sous-jacent.
la source