Ich habe das folgende Problem: Ich habe eine Datenbank mit mehr als 2 Millionen Datensätzen. Jeder Datensatz hat ein Zeichenkettenfeld X und ich möchte eine Liste von Datensätzen anzeigen, für die Feld X eine bestimmte Zeichenkette enthält. Jeder Datensatz ist ungefähr 500 Byte groß.
Um es konkreter zu machen: In der Benutzeroberfläche meiner Anwendung habe ich ein Textfeld, in das ich eine Zeichenfolge eingeben kann. Über dem Textfeld befindet sich eine Tabelle mit den (ersten N, z. B. 100) Datensätzen, die mit der Zeichenfolge im Textfeld übereinstimmen. Wenn ich ein Zeichen in das Textfeld eingebe oder lösche, muss der Tabelleninhalt sofort aktualisiert werden.
Ich frage mich, ob es einen effizienten Weg gibt, dies mit geeigneten Indexstrukturen und / oder Caching zu tun. Wie oben erläutert, möchte ich nur die ersten N Elemente anzeigen, die der Abfrage entsprechen. Daher sollte es für N, das klein genug ist, kein großes Problem sein, die übereinstimmenden Elemente aus der Datenbank zu laden. Außerdem kann das Zwischenspeichern von Elementen im Hauptspeicher das Abrufen beschleunigen.
Ich denke, das Hauptproblem ist, wie man die zusammenpassenden Einzelteile schnell findet, gegeben der Musterzeichenkette. Kann ich mich auf einige DBMS-Funktionen verlassen oder muss ich selbst einen speicherinternen Index erstellen? Irgendwelche Ideen?
BEARBEITEN
Ich habe ein erstes Experiment durchgeführt. Ich habe die Datensätze in verschiedene Textdateien aufgeteilt (höchstens 200 Datensätze pro Datei) und die Dateien in verschiedene Verzeichnisse gestellt (ich habe den Inhalt eines Datenfelds verwendet, um den Verzeichnisbaum zu bestimmen). Am Ende habe ich ungefähr 50000 Dateien in ungefähr 40000 Verzeichnissen. Ich habe dann Lucene ausgeführt, um die Dateien zu indizieren. Die Suche nach einer Zeichenfolge mit dem Lucene-Demoprogramm ist ziemlich schnell. Das Aufteilen und Indizieren dauerte einige Minuten. Dies ist für mich völlig akzeptabel, da es sich um einen statischen Datensatz handelt, den ich abfragen möchte.
Der nächste Schritt besteht darin, Lucene in das Hauptprogramm zu integrieren und die von Lucene zurückgegebenen Treffer zu verwenden, um die relevanten Datensätze in den Hauptspeicher zu laden.
quelle
Antworten:
Anstatt Ihre Daten in der Datenbank abzulegen, können Sie sie als eine Reihe von Dokumenten (Textdateien) separat aufbewahren und die Verknüpfung (Pfad / URL usw.) in der Datenbank aufbewahren.
Dies ist wichtig, da SQL-Abfragen aufgrund ihres Designs sowohl bei der Suche nach Unterzeichenfolgen als auch beim Abrufen sehr langsam sind.
Nun ist Ihr Problem so formuliert, dass Sie die Textdateien durchsuchen müssen, die die Zeichenfolgen enthalten. Hier gibt es zwei Möglichkeiten.
Übereinstimmung der Unterzeichenfolge Wenn Ihre Text-Blobs ein einzelnes Wort oder ein einzelnes Wort (ohne Leerzeichen) sind und Sie eine beliebige Unterzeichenfolge darin suchen müssen. In solchen Fällen müssen Sie jede Datei analysieren, um die bestmöglichen Dateien zu finden, die übereinstimmen. Man benutzt Algorithmen wie den Boyer Moor-Algorithmus. Siehe dies und das für Details. Dies ist auch gleichbedeutend mit grep - da grep ähnliche Inhalte verwendet. Aber Sie können immer noch mindestens 100 Grep (Worst Case 2 Millionen) machen, bevor Sie zurückkehren.
Indizierte Suche. In diesem Beispiel wird davon ausgegangen, dass der Text mehrere Wörter enthält und die Suche auf feste Wortlängen beschränkt ist. In diesem Fall wird das Dokument über alle möglichen Vorkommen von Wörtern indiziert. Dies wird häufig als "Volltextsuche" bezeichnet. Dazu gibt es eine Reihe von Algorithmen und Open Source-Projekte, die direkt verwendet werden können. Viele von ihnen unterstützen auch die Platzhaltersuche, die ungefähre Suche usw. wie folgt:
a. Apache Lucene: http://lucene.apache.org/java/docs/index.html
b. OpenFTS: http://openfts.sourceforge.net/
c. Sphinx http://sphinxsearch.com/
Wenn Sie "feste Wörter" als Abfragen benötigen, ist der zweite Ansatz höchstwahrscheinlich sehr schnell und effektiv.
quelle
Die Technologie, nach der Sie suchen, ist die Volltextindizierung. Die meisten RDBMS haben eine Art von integrierten Funktionen, die hier funktionieren könnten, oder Sie könnten etwas wie Lucene verwenden, wenn Sie schicker werden und / oder es einfach im Speicher ausführen möchten.
quelle
Hast du über einen Versuch nachgedacht ? Grundsätzlich erstellen Sie einen Baum mit gemeinsamen Präfixen, sodass alle Wörter, die mit denselben Buchstaben beginnen, untergeordnete Elemente desselben Knotens sind. Wenn Sie Matching für einen beliebigen Teilstring unterstützen möchten, müssen Sie eine Art permutierten Index generieren und daraus Ihren Versuch erstellen. Das kann jedoch dazu führen, dass Ihre Speicheranforderungen in die Knie gezwungen werden.
quelle
Ich möchte Wyatt Barnetts Antwort hinzufügen, dass eine RDBMS-Lösung mit Volltextindizierung für die entsprechende Spalte funktioniert. Wenn Sie jedoch einen lokalen Cache mit zuvor abgerufenen Datensätzen verwenden möchten, müssen Sie einen Plan erstellen, um diese zwischengespeicherten Datensätze zu verwenden zu Ihrem Vorteil.
Eine Möglichkeit besteht darin, die eindeutigen Bezeichner dieser Datensätze zu erfassen, die Sie AUSSCHLIESSLICH nicht aus der Abfrage abrufen möchten, und sie möglicherweise in a
NOT IN
oder a aufzunehmenNOT EXISTS
.Vorsichtshinweis: Die Verwendung von
NOT IN
oder istNOT EXISTS
in der Regel nicht billig und kann die Abfrageleistung oder den Abfrageplan je nach verwendetem Datenbankmodul negativ beeinflussen. Führen Sie einen EXPLAIN-Plan für Ihre endgültige Abfrage aus, um sicherzustellen, dass alle Ihre Indizes für die betroffenen Spalten verwendet werden.Es schadet auch nicht, einen Leistungsvergleich zwischen den beiden Ansätzen durchzuführen, um festzustellen, welche schneller sind. Es kann Sie überraschen, dass das Verwalten eines lokalen Caches und das explizite Filtern dieser aus Ihrer Abfrage möglicherweise eine schlechtere Leistung aufweist als eine fein abgestimmte Abfrage, die alle Datensätze abruft.
quelle
Nur für den Fall, dass Sie es verpasst haben. Wenn Sie für Ihre Datenbank Lucene anstelle einer von In-DB unterstützten Textsuche verwenden, müssen Sie beim Ändern Ihrer Datenbank äußerst vorsichtig sein. Wie stellen Sie sicher, dass Sie atomar arbeiten können, wenn Sie sowohl in der Datenbank als auch in den externen Ressourcen (Lucene) Änderungen vornehmen müssen? Ja, es kann getan werden, aber es wird viel Arbeit geben.
Kurz gesagt, Sie verlieren die DB-Transaktionsunterstützung, wenn Sie Lucene in Ihr Datenschema aufnehmen.
quelle
Haben Sie an Sphinx gedacht? http://sphinxsearch.com Wenn Sie ein Tool eines Drittanbieters verwenden können, ist dies ideal für das, was Sie erreichen möchten. Es ist bei der Volltextsuche viel effizienter als jedes RDBMS, das ich persönlich verwendet habe.
quelle
Es ist etwas seltsam, dass keine der Antworten den Begriff "invertierter Index" enthielt , die Technologie, die allen Lösungen ähnlich wie Apache Lucene und anderen zugrunde liegt.
Der invertierte Index ist eine Zuordnung von Wörtern zu Dokumenten ("invertierter Index auf Datensatzebene") oder sogar zu genauen Wortpositionen innerhalb des Dokuments ("invertierter Index auf Wortebene").
UND- und ODER-Verknüpfungen sind einfach zu implementieren. Wenn Sie über genaue Wortpositionen verfügen, können Sie nach benachbarten Wörtern suchen und so die Suche nach Phrasen ermöglichen.
Stellen Sie sich also einen Index vor, der Tupel (Wort, Datei, Speicherort) enthält. Wenn Sie zB ("inverted", "foo.txt", 123) haben, prüfen Sie einfach, ob ("index", "foo.txt", 124) Teil des Index ist, um nach der vollständigen Phrase "inverted index" zu suchen. .
Ich empfehle Ihnen zwar nicht, eine Volltextsuchmaschine von Grund auf neu zu implementieren, es ist jedoch hilfreich zu wissen, wie Technologien wie Apache Lucene funktionieren.
Daher empfehle ich, zu lernen, wie invertierte Indizes funktionieren, und eine Technologie wie Apache Lucene zu wählen. Dann haben Sie zumindest ein solides Verständnis dafür, was getan werden kann und was nicht.
quelle