web-dev-qa-db-fra.com

Algorithme de recherche floue (algorithme d'appariement de chaînes approximatif)

Je souhaite créer un algorithme de recherche floue. Cependant, après des heures de recherche, j'ai vraiment du mal.

Je veux créer un algorithme qui effectue une recherche floue sur une liste de noms d'écoles.

C'est ce que j'ai regardé jusqu'à présent:

La plupart de mes recherches continuent de pointer sur "métriques de chaîne" sur Google et Stackoverflow tels que:

  • distance Levenshtein
  • distance Damerau-Levenshtein
  • algorithme Needleman – Wunsch

Cependant, cela donne juste un score de la façon dont similaire 2 chaînes sont. La seule façon dont je peux penser à l'implémenter comme un algorithme de recherche est d'effectuer une recherche linéaire et d'exécuter l'algorithme de métrique de chaîne pour chaque chaîne et de renvoyer les chaînes avec des scores supérieurs à un certain seuil. (À l'origine, j'avais mes cordes stockées dans un arbre de trie, mais cela ne m'aidera évidemment pas ici!)

Bien que ce ne soit pas une si mauvaise idée pour les petites listes, ce serait problématique pour les listes avec disons 100 000 noms, et l'utilisateur a effectué de nombreuses requêtes.

Un autre algorithme que j'ai examiné est le méthode du correcteur orthographique, où vous effectuez simplement une recherche pour toutes les fautes d'orthographe potentielles. Cependant, cela est également très inefficace car il nécessite plus de 75 000 mots pour un mot de longueur 7 et un nombre d'erreurs de seulement 2.

De quoi ai-je besoin?

Quelqu'un peut-il me suggérer un bon algorithme de recherche floue efficace. avec:

  • Nom de l'algorithme
  • Comment ça marche ou un lien vers comment ça marche
  • Pour et contre et quand il est préférable de l'utiliser (facultatif)

Je comprends que tous les algorithmes auront leurs avantages et leurs inconvénients et qu'il n'y a pas meilleur algorithme.

44
Yahya Uddin

Étant donné que vous essayez de faire une recherche floue sur une liste de noms d'école, je ne pense pas que vous souhaitiez opter pour une similitude de chaîne traditionnelle comme la distance de Levenshtein. Mon hypothèse est que vous prenez la saisie d'un utilisateur (soit la saisie au clavier ou parlé au téléphone), et que vous souhaitez trouver rapidement l'école correspondante.

Les mesures de distance vous indiquent dans quelle mesure deux chaînes similaires sont basées sur des substitutions, des suppressions et des insertions. Mais ces algorithmes ne vous disent vraiment rien sur la similitude des chaînes avec les mots dans un langage humain.

Considérez, par exemple, les mots "forgeron", "smythe" et "smote". Je peux passer de "smythe" à "smith" en deux étapes:

smythe -> smithe -> smith

Et de "smote" à "smith" en deux étapes:

smote -> smite -> smith

Ainsi, les deux ont la même distance que les chaînes , mais comme les mots , ils sont très différents. Si quelqu'un vous disait (langue parlée) qu'il cherchait "Symthe College", vous diriez presque certainement: "Oh, je pense que vous voulez dire Smith." Mais si quelqu'un disait "Smote College", vous n'auriez aucune idée de quoi il parlait.

Ce dont vous avez besoin est un algorithme phonétique comme Soundex ou Metaphone . Fondamentalement, ces algorithmes décomposent un mot en phonèmes et créent une représentation de la façon dont le mot est prononcé dans la langue parlée. Vous pouvez ensuite comparer le résultat à une liste de mots connue pour trouver une correspondance.

Un tel système serait beaucoup plus rapide que l'utilisation d'une métrique de distance. Considérez qu'avec une mesure de distance, vous devez comparer l'entrée de l'utilisateur avec chaque mot de votre liste pour obtenir la distance. C'est coûteux en calcul et les résultats, comme je l'ai démontré avec "smith" et "smote" peuvent être ridiculement mauvais.

À l'aide d'un algorithme phonétique, vous créez la représentation phonémique de chacun de vos mots connus et la placez dans un dictionnaire (une carte de hachage ou éventuellement un trie). C'est un coût de démarrage unique. Ensuite, chaque fois que l'utilisateur saisit un terme de recherche, vous créez la représentation phonémique de son entrée et la recherchez dans votre dictionnaire. C'est beaucoup plus rapide et produit de bien meilleurs résultats.

Considérez également que lorsque les gens orthographient mal les noms propres, ils obtiennent presque toujours la première lettre correcte, et le plus souvent, prononcer l'orthographe sonne comme le vrai mot qu'ils essayaient d'épeler. Si tel est le cas, les algorithmes phonétiques sont définitivement la voie à suivre.

33
Jim Mischel

Vous confondez les algorithmes de recherche floue avec la mise en œuvre: une recherche floue d'un mot peut renvoyer 400 résultats de tous les mots qui ont une distance de Levenshtein de, disons, 2. Mais, pour l'utilisateur, vous devez afficher uniquement le top 5-10.

En termes d'implémentation, vous prétraitez tous les mots du dictionnaire et enregistrez les résultats dans une base de données. Les mots populaires (et leurs goûts flous) seront enregistrés dans la couche cache - vous n'aurez donc pas à frapper la base de données pour chaque demande.

Vous pouvez ajouter une couche AI ​​qui ajoutera les fautes d'orthographe les plus courantes et les ajoutera à la base de données. Et etc.

5
alfasin

J'ai écrit un article sur la façon dont j'ai implémenté une recherche floue:

https://medium.com/@Srekel/implementing-a-fuzzy-search-algorithm-for-the-debuginator-cacc349e6c55

L'implémentation est dans Github et est dans le domaine public, alors n'hésitez pas à y jeter un œil.

https://github.com/Srekel/the-debuginator/blob/master/the_debuginator.h#L1856

Les principes de base sont les suivants: divisez toutes les chaînes que vous recherchez en parties. Donc, si vous avez des chemins, "C:\documents\lol.txt" est peut-être "C", "documents", "lol", "txt".

Assurez-vous de mettre ces chaînes en minuscules pour vous assurer qu'elles ne respectent pas la casse. (Peut-être ne le faites que si la chaîne de recherche est entièrement en minuscules).

Faites ensuite correspondre votre chaîne de recherche à celle-ci. Dans mon cas, je veux le faire correspondre indépendamment de l'ordre, donc "loldoc" correspondrait toujours au chemin ci-dessus même si "lol" vient après "doc".

L'appariement doit avoir un certain score pour être bon. La partie la plus importante, je pense, est la correspondance consécutive , donc plus il y a de caractères directement les uns après les autres, mieux c'est. Donc "doc" est meilleur que "dcm".

Ensuite, vous voudrez probablement donner un score supplémentaire pour un match qui est au début d'une partie. Vous obtenez donc plus de points pour "doc" que pour "ocu".

Dans mon cas, je donne également plus de points pour faire correspondre l'extrémité d'une pièce.

Et enfin, vous voudrez peut-être envisager de donner des points supplémentaires pour faire correspondre la dernière partie (s). Cela rend la correspondance entre le nom de fichier et la fin plus élevée que les dossiers qui y mènent.

3
Srekel

Un algorithme simple pour "une sorte de recherche floue"

Pour être honnête, dans certains cas, la recherche floue est généralement inutile et je pense qu'un algorithme plus simple peut améliorer le résultat de la recherche tout en donnant l'impression que nous effectuons toujours une recherche floue.

Voici mon cas d'utilisation: Filtrage d'une liste de pays en utilisant la "Recherche floue" .

La liste avec laquelle je travaillais comprenait deux pays commençant par Z: la Zambie et le Zimbabwe.

J'utilisais Fusejs .

Dans ce cas, lors de la saisie de l'aiguille "zam", le jeu de résultats avait 19 correspondances et la plus pertinente pour tout humain (Zambie) en bas de la liste. Et la plupart des autres pays dans le résultat n'avaient même pas la lettre z dans leur nom.

C'était pour une application mobile où vous pouvez choisir un pays dans une liste. C'était censé être un peu comme lorsque vous devez choisir un contact parmi les contacts du téléphone. Vous pouvez filtrer la liste de contacts en saisissant un terme dans la zone de recherche.

À mon humble avis, ce type de contenu limité à rechercher ne doit pas être traité d'une manière qui obligera les gens à se demander "qu'est-ce qui se passe?!?".

On pourrait suggérer de trier par correspondance la plus pertinente. Mais c'est hors de question dans ce cas car l'utilisateur devra alors toujours trouver visuellement l '"Objet d'Intérêt" dans la liste réduite. Gardez à l'esprit qu'il s'agit d'un outil de filtrage et non d'un moteur de recherche "à la Google". Le résultat doit donc être trié de manière prévisible. Et avant le filtrage, le tri était alphabétique. La liste filtrée ne doit donc être qu'un sous-ensemble trié par ordre alphabétique de la liste d'origine.

J'ai donc trouvé l'algorithme suivant ...

  1. Prenez l'aiguille ... dans ce cas: zam
  2. Insérez le .* motif au début et à la fin de l'aiguille
  3. Insérez le .* motif entre chaque lettre de l'aiguille
  4. Effectuez une recherche Regex dans la botte de foin en utilisant la nouvelle aiguille qui est maintenant .*z.*a.*m.*

Dans ce cas, l'utilisateur aura un résultat très attendu en trouvant tout ce qui a en quelque sorte les lettres z, a et m apparaissant dans cet ordre. Toutes les lettres dans les aiguilles seront présentes dans les matchs dans le même ordre.

Cela correspondra également aux noms de pays comme Mo zam bique ... ce qui est parfait.

Je pense juste que parfois, nous ne devons pas essayer de tuer une mouche avec un bazooka.

2
asiby