it-swarm.com.de

So implementieren Sie die automatische Vervollständigung eines umfangreichen Datensatzes

Ich versuche, so etwas wie Google auf einer Website zu implementieren, die ich gerade baue, und bin neugierig, wie man mit einem sehr großen Datensatz umgehen kann. Sicher, wenn Sie 1000 Gegenstände haben, zwischenspeichern Sie die Gegenstände und blättern Sie einfach durch. Aber wie gehen Sie vor, wenn Sie eine Million Artikel haben? Angenommen, die Elemente sind kein Wort. Ich bin von Pandora.com wirklich sehr beeindruckt. Wenn Sie beispielsweise nach "nass" suchen, wird "Nasssand" zurückgegeben, aber es wird auch Toad The Wet Ritzel zurückgegeben. Und ihre Autovervollständigung ist SCHNELL. Meine erste Idee war, die Elemente nach den ersten beiden Buchstaben zu gruppieren, so dass Sie ungefähr Folgendes hätten:

Dictionary<string,List<string>>

wobei der Schlüssel die ersten zwei Buchstaben ist. Das ist in Ordnung, aber was ist, wenn ich etwas Ähnliches wie Pandora machen möchte und dem Benutzer erlauben würde, Ergebnisse zu sehen, die mit der Mitte der Zeichenfolge übereinstimmen? Mit meiner Idee: Wet würde niemals mit Toad the Wet Ritzel übereinstimmen, da es sich im "TO" -Behälter anstatt im "WE" -Behälter befinden würde. Dann könnte man vielleicht könnte die Saite aufteilen und "Toad the Wet Sprocket" in die "TO", "WE" und "SP" -Behälter gehen (streichen Sie das Wort "THE" aus), aber wenn Sie sind Wenn es um eine Million Einträge geht, die möglicherweise ein paar Worte zu sagen haben, scheint es, als würden Sie schnell viel Speicher verbrauchen. Ok, das war eine lange Frage. Gedanken? 

41
aquinas

Wie ich in How to incremental search auf einer Liste verwiesen habe sollten Sie Strukturen wie Trie oder Patricia Trie verwenden, um Muster in großen Texten zu suchen.

Und um Muster in der Mitte eines Textes zu entdecken, gibt es eine einfache Lösung. Ich bin nicht sicher, ob es die effizienteste Lösung ist, aber ich mache es normalerweise wie folgt.

Wenn ich neuen Text in den Trie einfüge, füge ich ihn einfach ein, entferne dann das erste Zeichen, füge es erneut ein, entferne das zweite Zeichen, füge es wieder ein ... und so weiter, bis der gesamte Text verbraucht ist. Dann können Sie jeden Teilstring jedes eingefügten Textes durch eine einzige Suche von der Wurzel aus entdecken. Diese resultierende Struktur wird als Suffix-Baum bezeichnet, und es stehen viele Optimierungen zur Verfügung.

Und es ist wirklich unglaublich schnell. Um alle Texte zu finden, die eine bestimmte Folge von n Zeichen enthalten, müssen Sie höchstens n Knoten untersuchen und eine Suche in der Liste der untergeordneten Elemente für jeden Knoten durchführen. Abhängig von der Implementierung (Array, Liste, binärer Baum, Übersprungsliste) der untergeordneten Knotenauflistung können Sie den erforderlichen untergeordneten Knoten möglicherweise mit nur fünf Suchschritten identifizieren, sofern nur lateinische Groß-/Kleinschreibung verwendet wird. Die Interpolationssortierung kann für große Alphabete und Knoten mit vielen untergeordneten Elementen hilfreich sein, da sich diese normalerweise in der Nähe der Wurzel befinden.

27

Versuchen Sie nicht, dies selbst zu implementieren (es sei denn, Sie sind nur neugierig). Verwenden Sie etwas wie Lucene oder Endeca - es spart Ihnen Zeit und Haare.

8
Jim Arnold

Sie sind nicht algorithmisch mit dem, was Sie fragen, aber stellen Sie sicher, dass Sie nach dem Kaypress (es) eine Verzögerung von 200 ms oder mehr haben, um sicherzustellen, dass der Benutzer die Eingabe abgebrochen hat, bevor Sie die asynchrone Anforderung absetzen. Auf diese Weise reduzieren Sie redundante HTTP-Anforderungen an den Server.

4
cherouvim

Ich würde etwas im Sinne von trie verwenden, und der Wert jedes Blattknotens sei eine Liste der Möglichkeiten, die das durch den Blattknoten dargestellte Wort enthalten. Sie können sie nach der Wahrscheinlichkeit sortieren oder dynamisch nach anderen Wörtern sortieren/filtern, die der Benutzer in das Suchfeld eingegeben hat usw. Diese Funktion wird sehr schnell und in einem angemessenen Arbeitsspeicher ausgeführt.

2
rmeador

wenn Sie keinen Trie wünschen und Dinge aus der Mitte der Saite möchten, möchten Sie im Allgemeinen eine Art Distanzentfernungsfunktion (Levenshtein-Distanz) ausführen, die Ihnen eine Zahl gibt, die angibt, wie gut 2 Saiten zusammenpassen. Es ist kein besonders effizienter Algorithmus, aber für Dinge wie Wörter ist es nicht so wichtig, da sie relativ kurz sind. Wenn Sie Vergleiche mit 8000 Zeichenfolgen durchführen, wird dies wahrscheinlich einige Sekunden dauern. Ich weiß, dass die meisten Sprachen über eine Implementierung verfügen, oder Sie können Code/Pseudocode dafür ganz einfach im Internet finden.

1
Ian Ooi

Sie behalten die Elemente auf der Serverseite (möglicherweise in einer Datenbank, wenn die Datenmenge wirklich groß und komplex ist), und Sie senden AJAX -Anrufe vom Browser des Clients, die die Ergebnisse mit json/xml zurückgeben. Sie können dies als Reaktion auf die Eingabe des Benutzers oder mit einem Timer tun.

1
Assaf Lavie

Ich habe AutoCompleteAPI für dieses Szenario genau gebaut. 

Registrieren Sie sich, um ein privates Verzeichnis zu erhalten, dann Laden Sie Ihre Dokumente hoch.

Beispiel-Upload mit curl in Dokument "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]"

Verwenden Sie nach der Indizierung des gesamten Dokuments Folgendes:

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

Sie können jede Client-Autovervollständigungsbibliothek verwenden, um dem Benutzer diese Ergebnisse anzuzeigen. 

0
Sean