J'ai besoin d'un moyen de comparer plusieurs chaînes à une chaîne de test et de renvoyer la chaîne qui lui ressemble de très près:
TEST STRING: THE BROWN FOX JUMPED OVER THE RED COW
CHOICE A : THE RED COW JUMPED OVER THE GREEN CHICKEN
CHOICE B : THE RED COW JUMPED OVER THE RED COW
CHOICE C : THE RED FOX JUMPED OVER THE BROWN COW
(Si je l'ai fait correctement) La chaîne la plus proche de "TEST STRING" devrait être "CHOICE C". Quelle est la manière la plus simple de faire ça?
Je prévois de mettre cela en œuvre dans plusieurs langues, notamment VB.net, Lua et JavaScript. À ce stade, le pseudo-code est acceptable. Si vous pouvez fournir un exemple pour une langue spécifique, vous l'apprécierez également!
On m'a présenté ce problème il y a environ un an lorsqu'il est venu de rechercher des informations saisies par un utilisateur sur une plate-forme pétrolière dans une base de données d'informations diverses. L'objectif était de faire une sorte de recherche de chaîne floue pouvant identifier l'entrée de base de données avec les éléments les plus communs.
Une partie de la recherche a impliqué la mise en œuvre de l’algorithme Levenshtein distance , qui détermine le nombre de modifications à apporter à une chaîne ou à une phrase pour la transformer en une autre chaîne ou en une autre phrase.
L'implémentation que j'ai proposée était relativement simple et impliquait une comparaison pondérée de la longueur des deux phrases, du nombre de changements entre chaque phrase et de la possibilité de trouver chaque mot dans l'entrée cible.
L'article est sur un site privé, je vais donc faire de mon mieux pour ajouter le contenu pertinent ici:
La correspondance de chaîne floue est le processus consistant à effectuer une estimation de la similarité de deux mots ou expressions à la manière d'un homme. Dans de nombreux cas, il s’agit d’identifier des mots ou des expressions qui se ressemblent le plus. Cet article décrit une solution interne au problème de correspondance de chaîne floue et son utilité pour la résolution de divers problèmes nous permettant d'automatiser des tâches qui nécessitaient auparavant une implication fastidieuse de l'utilisateur.
Introduction
La nécessité de faire de la correspondance de chaîne fuzzy est apparue lors du développement de l'outil de validation du golfe du Mexique. Ce qui existait déjà était une base de données de plates-formes pétrolières et de plates-formes pétrolières connues dans le golfe du Mexique, et les acheteurs d'assurance nous donnaient des informations mal typées sur leurs actifs et nous devions les faire correspondre à la base de données de plates-formes connues. Lorsque très peu d’informations sont données, le mieux que nous puissions faire est de nous fier à un souscripteur pour "reconnaître" celui auquel il faisait référence et pour obtenir les informations appropriées. C’est là que cette solution automatisée devient pratique.
J'ai passé une journée à rechercher des méthodes de correspondance de chaîne fuzzy et suis finalement tombé sur le très utile algorithme de distance Levenshtein sur Wikipedia.
Mise en oeuvre
Après avoir lu sur la théorie derrière, j’ai mis en œuvre et trouvé des moyens de l’optimiser. Voici à quoi ressemble mon code dans VBA:
'Calculate the Levenshtein Distance between two strings (the number of insertions,
'deletions, and substitutions needed to transform the first string into the second)
Public Function LevenshteinDistance(ByRef S1 As String, ByVal S2 As String) As Long
Dim L1 As Long, L2 As Long, D() As Long 'Length of input strings and distance matrix
Dim i As Long, j As Long, cost As Long 'loop counters and cost of substitution for current letter
Dim cI As Long, cD As Long, cS As Long 'cost of next Insertion, Deletion and Substitution
L1 = Len(S1): L2 = Len(S2)
ReDim D(0 To L1, 0 To L2)
For i = 0 To L1: D(i, 0) = i: Next i
For j = 0 To L2: D(0, j) = j: Next j
For j = 1 To L2
For i = 1 To L1
cost = Abs(StrComp(Mid$(S1, i, 1), Mid$(S2, j, 1), vbTextCompare))
cI = D(i - 1, j) + 1
cD = D(i, j - 1) + 1
cS = D(i - 1, j - 1) + cost
If cI <= cD Then 'Insertion or Substitution
If cI <= cS Then D(i, j) = cI Else D(i, j) = cS
Else 'Deletion or Substitution
If cD <= cS Then D(i, j) = cD Else D(i, j) = cS
End If
Next i
Next j
LevenshteinDistance = D(L1, L2)
End Function
Simple, rapide et une métrique très utile. À l'aide de cela, j'ai créé deux métriques distinctes pour évaluer la similarité de deux chaînes. J'appelle "valuePhrase" et l'autre "valueWords". valuePhrase est juste la distance de Levenshtein entre les deux phrases, et valueWords divise la chaîne en mots individuels, en fonction de délimiteurs tels que des espaces, des tirets et tout ce que vous voulez, et compare chaque mot à un autre mot, en résumant le plus court Distance de Levenshtein reliant deux mots quelconques. Essentiellement, il mesure si les informations contenues dans une "phrase" sont réellement contenues dans une autre, à la manière d'une permutation fondée sur le mot. J'ai passé quelques jours en tant que projet parallèle à trouver le moyen le plus efficace possible de scinder une chaîne en fonction de délimiteurs.
valueWords, valuePhrase et Split:
Public Function valuePhrase#(ByRef S1$, ByRef S2$)
valuePhrase = LevenshteinDistance(S1, S2)
End Function
Public Function valueWords#(ByRef S1$, ByRef S2$)
Dim wordsS1$(), wordsS2$()
wordsS1 = SplitMultiDelims(S1, " _-")
wordsS2 = SplitMultiDelims(S2, " _-")
Dim Word1%, Word2%, thisD#, wordbest#
Dim wordsTotal#
For Word1 = LBound(wordsS1) To UBound(wordsS1)
wordbest = Len(S2)
For Word2 = LBound(wordsS2) To UBound(wordsS2)
thisD = LevenshteinDistance(wordsS1(Word1), wordsS2(Word2))
If thisD < wordbest Then wordbest = thisD
If thisD = 0 Then GoTo foundbest
Next Word2
foundbest:
wordsTotal = wordsTotal + wordbest
Next Word1
valueWords = wordsTotal
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' SplitMultiDelims
' This function splits Text into an array of substrings, each substring
' delimited by any character in DelimChars. Only a single character
' may be a delimiter between two substrings, but DelimChars may
' contain any number of delimiter characters. It returns a single element
' array containing all of text if DelimChars is empty, or a 1 or greater
' element array if the Text is successfully split into substrings.
' If IgnoreConsecutiveDelimiters is true, empty array elements will not occur.
' If Limit greater than 0, the function will only split Text into 'Limit'
' array elements or less. The last element will contain the rest of Text.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function SplitMultiDelims(ByRef Text As String, ByRef DelimChars As String, _
Optional ByVal IgnoreConsecutiveDelimiters As Boolean = False, _
Optional ByVal Limit As Long = -1) As String()
Dim ElemStart As Long, N As Long, M As Long, Elements As Long
Dim lDelims As Long, lText As Long
Dim Arr() As String
lText = Len(Text)
lDelims = Len(DelimChars)
If lDelims = 0 Or lText = 0 Or Limit = 1 Then
ReDim Arr(0 To 0)
Arr(0) = Text
SplitMultiDelims = Arr
Exit Function
End If
ReDim Arr(0 To IIf(Limit = -1, lText - 1, Limit))
Elements = 0: ElemStart = 1
For N = 1 To lText
If InStr(DelimChars, Mid(Text, N, 1)) Then
Arr(Elements) = Mid(Text, ElemStart, N - ElemStart)
If IgnoreConsecutiveDelimiters Then
If Len(Arr(Elements)) > 0 Then Elements = Elements + 1
Else
Elements = Elements + 1
End If
ElemStart = N + 1
If Elements + 1 = Limit Then Exit For
End If
Next N
'Get the last token terminated by the end of the string into the array
If ElemStart <= lText Then Arr(Elements) = Mid(Text, ElemStart)
'Since the end of string counts as the terminating delimiter, if the last character
'was also a delimiter, we treat the two as consecutive, and so ignore the last elemnent
If IgnoreConsecutiveDelimiters Then If Len(Arr(Elements)) = 0 Then Elements = Elements - 1
ReDim Preserve Arr(0 To Elements) 'Chop off unused array elements
SplitMultiDelims = Arr
End Function
Mesures de similarité
En utilisant ces deux métriques, et une troisième qui calcule simplement la distance entre deux chaînes, j'ai une série de variables sur lesquelles je peux exécuter un algorithme d'optimisation pour obtenir le plus grand nombre de correspondances. La correspondance de chaîne floue est, en soi, une science floue. Ainsi, en créant des métriques linéairement indépendantes pour mesurer la similarité de chaîne, et en ayant un ensemble connu de chaînes que nous souhaitons faire correspondre, nous pouvons trouver les paramètres qui, pour nos styles spécifiques de cordes, donner les meilleurs résultats de correspondance floue.
Initialement, l'objectif de la métrique était de définir une valeur de recherche faible pour une correspondance exacte et d'augmenter les valeurs de recherche pour des mesures de plus en plus permutées. Dans un cas peu pratique, il était assez facile de définir cela à l’aide d’un ensemble de permutations bien définies et d’ingénierie de la formule finale de sorte que les résultats des valeurs de recherche soient croissants à volonté.
Dans la capture d'écran ci-dessus, j'ai peaufiné mon heuristique pour proposer quelque chose que je sentais parfaitement adapté à ma différence perçue entre le terme de recherche et le résultat. L'heuristique que j'ai utilisée pour Value Phrase
dans le tableur ci-dessus était =valuePhrase(A2,B2)-0.8*ABS(LEN(B2)-LEN(A2))
. Je réduisais effectivement la pénalité de la distance de Levenstein de 80% de la différence de longueur des deux "phrases". De cette façon, les "phrases" qui ont la même durée sont punies de la peine totale, mais les "phrases" qui contiennent des "informations supplémentaires" (plus longues), mais qui partagent la plupart du temps les mêmes caractères, sont soumises à une peine réduite. J'ai utilisé la fonction Value Words
telle quelle, puis mon heuristique finale SearchVal
a été définie comme étant =MIN(D2,E2)*0.8+MAX(D2,E2)*0.2
- une moyenne pondérée. Le plus faible des deux scores a été pondéré à 80% et 20% du score le plus élevé. C’était juste une heuristique qui convenait à mon cas d’utilisation pour obtenir un bon taux de correspondance. Ces poids sont quelque chose que l’on pourrait ensuite modifier pour obtenir le meilleur taux de correspondance avec leurs données de test.
Comme vous pouvez le constater, les deux dernières métriques, qui sont des métriques de correspondance de chaîne floue, ont déjà une tendance naturelle à donner des scores bas aux chaînes censées correspondre (en diagonale). C'est très bien.
Application Pour permettre l'optimisation de la correspondance floue, pondérer chaque métrique. En tant que telle, chaque application de correspondance de chaîne floue peut pondérer les paramètres différemment. La formule qui définit le score final est une simple combinaison des métriques et de leur poids:
value = Min(phraseWeight*phraseValue, wordsWeight*wordsValue)*minWeight
+ Max(phraseWeight*phraseValue, wordsWeight*wordsValue)*maxWeight
+ lengthWeight*lengthValue
En utilisant un algorithme d'optimisation (le réseau de neurones est préférable ici car il s'agit d'un problème discret et multidimensionnel), l'objectif est maintenant de maximiser le nombre de correspondances. J'ai créé une fonction qui détecte le nombre de correspondances correctes de chaque ensemble, comme on peut le voir dans cette dernière capture d'écran. Une colonne ou une ligne obtient un point si le score le plus bas est attribué à la chaîne qui devait être mise en correspondance, et des points partiels sont attribués s'il existe une égalité pour le score le plus bas et si la correspondance correcte se trouve parmi les chaînes mises en correspondance. Je l'ai ensuite optimisé. Vous pouvez voir qu'une cellule verte est la colonne qui correspond le mieux à la ligne actuelle et qu'un carré bleu autour de la cellule correspond à la ligne qui correspond le mieux à la colonne actuelle. Le score dans le coin inférieur est à peu près le nombre de correspondances réussies et c’est ce que nous disons maximiser notre problème d’optimisation.
L'algorithme a été un succès retentissant et les paramètres de la solution en disent long sur ce type de problème. Vous remarquerez que le score optimisé était 44, et le meilleur score possible est 48. Les 5 colonnes à la fin sont des leurres et n'ont aucune correspondance avec les valeurs de la ligne. Plus les leurres sont nombreux, plus il sera naturellement difficile de trouver le meilleur match.
Dans ce cas particulier, la longueur des chaînes n'a aucune importance, car nous attendons des abréviations représentant des mots plus longs. Par conséquent, le poids optimal pour la longueur est de -0,3, ce qui signifie que nous ne pénalisons pas les chaînes dont la longueur varie. Nous réduisons le score en prévision de ces abréviations, ce qui laisse plus de place aux correspondances partielles dans Word pour remplacer les correspondances autres que Word qui nécessitent simplement moins de substitutions, car la chaîne est plus courte.
La pondération des mots est de 1,0 alors que celle de la phrase n'est que de 0,5, ce qui signifie que nous pénalisons les mots entiers manquants d'une chaîne et valorisons davantage la phrase entière qui est intacte. Ceci est utile car beaucoup de ces chaînes ont un mot commun (le péril) où l’important est de savoir si la combinaison (région et péril) est conservée.
Enfin, le poids minimum est optimisé à 10 et le poids maximum à 1. Cela signifie que si le meilleur des deux scores (phrase valeur et mots valeur) n’est pas très bon, la correspondance est grandement pénalisée, mais nous ne le faisons pas. pas beaucoup pénaliser le pire des deux scores. Cela met essentiellement l'accent sur l'obligation soit que valueWord ou valuePhrase donne un bon score, mais pas les deux. Une sorte de "prendre ce que nous pouvons obtenir" mentalité.
C'est vraiment fascinant ce que dit la valeur optimisée de ces 5 poids sur le type de correspondance de chaîne fuzzy en cours. Pour des cas complètement différents de correspondance de chaîne fuzzy, ces paramètres sont très différents. Je l'ai utilisé pour 3 applications distinctes jusqu'à présent.
Bien que l’optimisation finale n’ait pas été utilisée, une feuille de comparaison a été établie, qui correspond aux colonnes pour obtenir des résultats parfaits sur toute la diagonale et permet à l’utilisateur de modifier les paramètres pour contrôler le taux de divergence des scores par rapport à 0 et noter les similitudes innées entre les expressions de recherche ( qui pourrait en théorie être utilisé pour compenser les faux positifs dans les résultats)
Autres applications
Cette solution peut être utilisée partout où l'utilisateur souhaite qu'un système informatique identifie une chaîne dans un ensemble de chaînes où il n'y a pas de correspondance parfaite. (Comme une correspondance approximative avec vlookup pour les chaînes).
Vous devez donc probablement utiliser une combinaison d’heuristiques de haut niveau (recherche de mots d’une phrase dans l’autre phrase, longueur des deux phrases, etc.) et la mise en œuvre de l’algorithme de distance de Levenshtein. Parce que le choix de la "meilleure" correspondance est une détermination heuristique (floue) - vous devez définir un ensemble de pondérations pour toutes les métriques que vous proposez afin de déterminer la similarité.
Avec les heuristiques et les poids appropriés, votre programme de comparaison prendra rapidement les décisions que vous auriez prises.
Ce problème se pose tout le temps en bioinformatique. La réponse acceptée ci-dessus (qui était excellente en passant) est connue en bioinformatique sous les algorithmes de Needleman-Wunsch (comparer deux chaînes) et de Smith-Waterman (trouver une sous-chaîne approximative dans une chaîne plus longue). Ils fonctionnent très bien et sont des chevaux de travail depuis des décennies.
Mais que se passe-t-il si vous avez un million de chaînes à comparer? C'est un billion de comparaisons par paires, chacune d'entre elles étant O (n * m)! Les séquenceurs d’ADN modernes génèrent facilement une milliard séquences courtes d’ADN, d’une longueur d’environ 200 "lettres". En règle générale, nous voulons trouver, pour chacune de ces chaînes, la meilleure correspondance avec le génome humain (3 milliards de lettres). Clairement, l'algorithme de Needleman-Wunsch et ses parents ne feront pas l'affaire.
Ce "problème d'alignement" est un domaine de recherche active. Les algorithmes les plus populaires sont actuellement capables de trouver des correspondances inexactes entre 1 milliard de chaînes courtes et le génome humain en quelques heures sur un matériel raisonnable (par exemple, huit cœurs et 32 Go de RAM).
La plupart de ces algorithmes fonctionnent en trouvant rapidement des correspondances exactes courtes (graines), puis en les étendant à la chaîne complète en utilisant un algorithme plus lent (par exemple, le Smith-Waterman). Cela fonctionne parce que nous ne sommes vraiment intéressés que par quelques matchs serrés. Il est donc avantageux de se débarrasser des 99,9 ...% de paires qui n'ont rien en commun.
Comment trouver des correspondances exactes aide-t-il à trouver des correspondances inexactes ? Eh bien, supposons que nous n'autorisons qu'une seule différence entre la requête et la cible. Il est facile de voir que cette différence doit apparaître dans la moitié droite ou gauche de la requête, l’autre moitié doit donc correspondre exactement. Cette idée peut être étendue à plusieurs mésappariements et constitue la base de l'algorithme ELAND couramment utilisé avec les séquenceurs d'ADN Illumina.
Il existe de nombreux très bons algorithmes pour la correspondance exacte de chaînes. Étant donné une chaîne de requête de longueur 200 et une chaîne cible de longueur 3 milliards (le génome humain), nous souhaitons trouver un emplacement dans la cible où se trouve une sous-chaîne de longueur k qui correspond exactement à une sous-chaîne de la requête. Une approche simple consiste à commencer par indexer la cible: prenez toutes les sous-chaînes de k-long, placez-les dans un tableau et triez-les. Ensuite, prenez chaque sous-chaîne longue de la requête et recherchez l'index trié. Trier et la recherche peut être effectuée en un temps O (log n).
Mais le stockage peut être un problème. Un index de la cible de 3 milliards de lettres devrait contenir 3 milliards de pointeurs et 3 milliards de mots. Il semblerait difficile d’adapter cela à moins de plusieurs dizaines de giga-octets de RAM. Mais étonnamment, nous pouvons grandement compresser l’indice, en utilisant le transformation de Burrows-Wheeler , et il sera toujours efficacement interrogeable. Un index du génome humain peut contenir moins de 4 Go de RAM. Cette idée est à la base des aligneurs de séquence populaires tels que Bowtie et BWA .
Alternativement, nous pouvons utiliser un suffix array , qui ne stocke que les pointeurs, tout en représentant un index simultané de tous les suffixes de la chaîne cible (essentiellement, un index simultané pour toutes les valeurs possibles de k; le même est vrai de la transformation de Burrows-Wheeler). Un index de suffixe du génome humain nécessitera 12 Go de RAM si nous utilisons des pointeurs 32 bits.
Les liens ci-dessus contiennent une mine d'informations et des liens vers des documents de recherche primaires. Le lien ELAND mène à un PDF avec des chiffres utiles illustrant les concepts en jeu et montre comment traiter les insertions et les suppressions.
Enfin, bien que ces algorithmes aient en principe résolu le problème du (re) séquençage de génomes humains uniques (un milliard de chaînes courtes), la technologie de séquençage de l’ADN s’améliore encore plus rapidement que la loi de Moore et nous approchons rapidement des ensembles de données de plusieurs milliards de lettres. Par exemple, des projets sont actuellement en cours pour séquencer les génomes de 10 000 espèces de vertébrés , comptant chacun un milliard de lettres. Naturellement, nous voudrons faire une correspondance inexacte des paires de chaînes sur les données ...
Je conteste que le choix B soit plus proche de la chaîne de test, car il ne s'agit que de 4 caractères (et 2 suppressions) de la chaîne d'origine. Tandis que vous voyez C comme plus proche, car il comprend à la fois le brun et le rouge. Il aurait cependant une plus grande distance d'édition.
Il existe un algorithme appelé Distance de Levenshtein qui mesure la distance d'édition entre deux entrées.
Here est un outil pour cet algorithme.
EDIT: Désolé, je continue à mélanger des chaînes dans l'outil levenshtein. Mis à jour pour corriger les réponses.
Lua mise en œuvre, pour la postérité:
function levenshtein_distance(str1, str2)
local len1, len2 = #str1, #str2
local char1, char2, distance = {}, {}, {}
str1:gsub('.', function (c) table.insert(char1, c) end)
str2:gsub('.', function (c) table.insert(char2, c) end)
for i = 0, len1 do distance[i] = {} end
for i = 0, len1 do distance[i][0] = i end
for i = 0, len2 do distance[0][i] = i end
for i = 1, len1 do
for j = 1, len2 do
distance[i][j] = math.min(
distance[i-1][j ] + 1,
distance[i ][j-1] + 1,
distance[i-1][j-1] + (char1[i] == char2[j] and 0 or 1)
)
end
end
return distance[len1][len2]
end
Vous pourriez être intéressé par cet article de blog.
http://seatgeek.com/blog/dev/fuzzywuzzy-fuzzy-string-matching-in-python
Fuzzywuzzy est une bibliothèque Python qui fournit des mesures de distance faciles, telles que la distance de Levenshtein pour la correspondance des chaînes. Il est construit sur la base de difflib dans la bibliothèque standard et utilisera l’implémentation C de Python-levenshtein si elle est disponible.
Vous pourriez trouver cette bibliothèque utile! http://code.google.com/p/google-diff-match-patch/
Il est actuellement disponible en Java, JavaScript, Dart, C++, C #, Objective C, Lua et Python.
Cela fonctionne plutôt bien aussi. Je l'utilise dans quelques-uns de mes projets Lua.
Et je ne pense pas qu'il serait trop difficile de le porter dans d'autres langues!
Si vous le faites dans le contexte d'un moteur de recherche ou d'une interface par rapport à une base de données, vous pouvez envisager d'utiliser un outil tel que Apache Solr , avec le plugin ComplexPhraseQueryParser . Cette combinaison vous permet de rechercher un index de chaînes avec les résultats triés par pertinence, comme déterminé par la distance de Levenshtein.
Nous l'utilisons contre une grande collection d'artistes et de titres de chansons lorsque la requête entrante peut comporter une ou plusieurs fautes de frappe et que cela fonctionne assez bien (et remarquablement rapidement, compte tenu du fait que les collections comptent des millions de chaînes).
En outre, avec Solr, vous pouvez effectuer une recherche à la demande sur l'index via JSON, de sorte que vous n'aurez pas à réinventer la solution entre les différentes langues que vous consultez.
Simmetrics est une très, très bonne ressource pour ce type d’algorithmes: http://sourceforge.net/projects/simmetrics/
Malheureusement, le site Web génial contenant une grande partie de la documentation a disparu :( Au cas où il reviendrait, son adresse précédente était la suivante: http://www.dcs.shef.ac.uk/~sam/simmetrics .html
Voila (avec la permission de "Wayback Machine"): http://web.archive.org/web/20081230184321/http://www.dcs.shef.ac.uk/~sam/simmetrics.html =
Vous pouvez étudier le code source. Il existe des dizaines d’algorithmes pour ce type de comparaison, chacun avec un compromis différent. Les implémentations sont en Java.
Le problème est difficile à mettre en œuvre si les données d'entrée sont trop volumineuses (disons des millions de chaînes). J'ai utilisé une recherche élastique pour résoudre ce problème.
Démarrage rapide: https://www.elastic.co/guide/en/elasticsearch/client/net-api/6.x/elasticsearch-net.html
Il suffit d'insérer toutes les données d'entrée dans la base de données et vous pouvez rechercher rapidement n'importe quelle chaîne en fonction de la distance d'édition. Voici un extrait de code C # qui vous donnera une liste de résultats triés par la distance d'édition (du plus petit au plus élevé).
var res = client.Search<ClassName>(s => s
.Query(q => q
.Match(m => m
.Field(f => f.VariableName)
.Query("SAMPLE QUERY")
.Fuzziness(Fuzziness.EditDistance(5))
)
));
Pour interroger efficacement un grand ensemble de texte, vous pouvez utiliser le concept Éditer Distance/Préfixe Éditer Distance.
Editer Distance ED (x, y): nombre minimal de transfroms pour aller du terme x au terme y
Cependant, le calcul de l'ED entre chaque terme et le texte de la requête prend beaucoup de temps et de ressources. Par conséquent, au lieu de calculer d'abord l'ED pour chaque terme, nous pouvons extraire les termes d'appariement possibles à l'aide d'une technique appelée Index Qgram. puis appliquez le calcul ED sur ces termes sélectionnés.
Un avantage de la technique d'indexation Qgram est qu'elle prend en charge la recherche floue.
Une approche possible pour adapter l'index QGram consiste à créer un index inversé à l'aide de Qgrams. Nous y stockons tous les mots qui consistent en un Qgram particulier, sous ce Qgram (au lieu de stocker une chaîne complète, vous pouvez utiliser un ID unique pour chaque chaîne). Vous pouvez utiliser la structure de données Tree Map dans Java pour cela. Voici un petit exemple sur la mémorisation des termes
col: col mbia, col ombo, gan col a, ta col AMA
Ensuite, lors d’une requête, nous calculons le nombre de Qgrams communs entre le texte de la requête et les termes disponibles.
Example: x = HILLARY, y = HILARI(query term)
Qgrams
$$HILLARY$$ -> $$H, $HI, HIL, ILL, LLA, LAR, ARY, RY$, Y$$
$$HILARI$$ -> $$H, $HI, HIL, ILA, LAR, ARI, RI$, I$$
number of q-grams in common = 4
nombre de q-grammes en commun = 4.
Pour les termes avec un nombre élevé de programmes communs, nous calculons l'ED/PED par rapport au terme de la requête, puis suggérons le terme à l'utilisateur final.
vous pouvez trouver une implémentation de cette théorie dans le projet suivant (Voir "QGramIndex.Java"). N'hésitez pas à poser des questions. https://github.com/Bhashitha-Gamage/City_Search
Pour en savoir plus sur Éditer Distance, Préfixe Éditer Distance Index Qgram, regardez la vidéo suivante du Prof. Dr Hannah Bast https://www.youtube.com/embed/6pUg2wmGJRo (la leçon commence à 20:06 )