web-dev-qa-db-fra.com

Comment implémenter la saisie semi-automatique sur un ensemble de données volumineux

J'essaie d'implémenter quelque chose comme Google suggère sur un site Web que je suis en train de construire et je suis curieux de savoir comment en faire un très grand ensemble de données. Bien sûr, si vous avez 1 000 éléments, vous les mettez en cache et les parcourez en boucle. Mais comment vous y prenez-vous quand vous avez un million d'articles? De plus, supposons que les éléments ne soient pas un seul mot. Plus précisément, j'ai été vraiment impressionné par Pandora.com. Par exemple, si vous recherchez «humide», cela ramène «sable humide» mais cela ramène également Toad The Wet Sprocket. Et leur autocomplete est rapide. Ma première idée était de regrouper les éléments en fonction des deux premières lettres, de sorte que vous obteniez quelque chose comme:

Dictionary<string,List<string>>

où la clé est les deux premières lettres. Ce n'est pas grave, mais que se passe-t-il si je veux faire quelque chose de similaire à Pandora et permettre à l'utilisateur de voir les résultats qui correspondent au milieu de la chaîne? Avec mon idée: Wet ne correspondrait jamais à Toad the Wet Sprocket, car ce serait dans le seau "TO" au lieu du seau "WE". Alors peut-être que vous pourriez séparer la chaîne et "Toad the Wet Sprocket" aller dans les compartiments "TO", "WE" et "SP" (effacez le mot "THE"), mais lorsque vous Parlez d’un million d’entrées qui peuvent avoir à dire quelques mots chacune, ce qui vous donne l’impression que vous allez commencer à utiliser rapidement beaucoup de mémoire. Ok, c'était une longue question. Pensées? 

41
aquinas

Comme je l'ai indiqué dans Comment mettre en œuvre la recherche incrémentielle sur une liste , vous devez utiliser des structures telles que Trie ou Patricia trie pour rechercher des modèles dans des textes volumineux.

Et pour découvrir des motifs au milieu d'un texte, il existe une solution simple. Je ne suis pas sûr que ce soit la solution la plus efficace, mais je le fais généralement comme suit.

Lorsque j'insère un nouveau texte dans le Trie, je l'insère simplement, puis supprime le premier caractère, insère à nouveau, supprime le deuxième caractère, réinsère ... et ainsi de suite jusqu'à ce que tout le texte soit consommé. Vous pouvez ensuite découvrir chaque sous-chaîne de chaque texte inséré en effectuant une seule recherche à partir de la racine. Cette structure résultante s'appelle un arbre de suffixe et de nombreuses optimisations sont disponibles.

Et c'est vraiment incroyable rapide. Pour rechercher tous les textes contenant une séquence donnée de n caractères, vous devez inspecter au maximum n nœuds et effectuer une recherche dans la liste des enfants pour chaque nœud. Selon l'implémentation (tableau, liste, arborescence binaire, liste à ignorer) de la collection de nœuds enfants, vous pourrez peut-être identifier le nœud enfant requis avec seulement 5 étapes de recherche en supposant que les lettres latines ne respectent pas la casse. Le tri par interpolation peut être utile pour les grands alphabets et les nœuds comportant un grand nombre d'enfants comme ceux généralement situés près de la racine.

27
Daniel Brückner

N'essayez pas de le mettre en œuvre vous-même (sauf si vous êtes simplement curieux). Utilisez quelque chose comme Lucene ou Endeca - cela vous fera gagner du temps et des cheveux.

8
Jim Arnold

Pas d'algorithme lié à ce que vous demandez, mais assurez-vous que vous avez un délai (retard) de 200 ms ou plus après le (s) message (s) afin de vous assurer que l'utilisateur a cessé de taper avant d'envoyer la demande asynchrone. De cette façon, vous réduirez les demandes HTTP redondantes sur le serveur.

4
cherouvim

Je voudrais utiliser quelque chose le long des lignes d'un trie , et avoir la valeur de chaque nœud feuille une liste des possibilités contenant le mot représenté par le nœud feuille. Vous pouvez les trier par ordre de probabilité ou les trier/filtrer de manière dynamique en fonction d'autres mots que l'utilisateur a entrés dans le champ de recherche, etc. Il s'exécutera très rapidement et avec une quantité raisonnable de RAM.

2
rmeador

si vous ne voulez pas d'essayer et que vous voulez des éléments du milieu de la chaîne, vous souhaitez généralement exécuter une sorte de fonction de modification de distance (levenshtein distance) qui vous donnera un numéro indiquant comment 2 chaînes correspondent. Ce n'est pas un algorithme particulièrement efficace, mais cela n'a pas beaucoup d'importance pour des mots comme les mots, car ils sont relativement courts. Si vous effectuez des comparaisons sur 8000 chaînes de caractères similaires, cela prendra probablement quelques secondes. Je sais que la plupart des langues ont une implémentation, ou vous pouvez trouver le code/pseudocode pour cela assez facilement sur Internet.

1
Ian Ooi

Vous conservez les éléments côté serveur (peut-être dans une base de données, si l'ensemble de données est vraiment volumineux et complexe) et envoyez des appels AJAX à partir du navigateur du client qui renvoient les résultats à l'aide de json/xml. Vous pouvez le faire en réponse à la saisie de l'utilisateur ou avec une minuterie.

1
Assaf Lavie

J'ai construit AutoCompleteAPI pour ce scénario exactement. 

Inscrivez-vous pour obtenir un index privé, puis, Téléchargez vos documents.

Exemple de téléchargement à l'aide de curl sur le document "New York": 

curl -X PUT -H "Content-Type: application/json" -H "Authorization: [YourSecretKey]" -d '{
"key": "New York",
"input": "New York"
}' "http://suggest.autocompleteapi.com/[YourAccountKey]/[FieldName]"

Après avoir indexé tous les documents, pour obtenir des suggestions de saisie semi-automatique, utilisez:

http://suggest.autocompleteapi.com/[YourAccountKey]/[FieldName]?prefix=new

Vous pouvez utiliser n'importe quelle bibliothèque de client autocomplete pour afficher ces résultats à l'utilisateur. 

0
Sean