Volltextsuche unter MySql
Simon
- datenbank
Hallo Leute!
Ich habe unter MySql 3.23.52-nt eine Tabelle mit folgendem Schema angelegt:
create table TABELLE (
SL int not null auto_increment,
SPALTE1 char(120),
SPALTE2 text,
SPALTE3 text,
SPALTE4 char(60),
SPALTE5 int,
fulltext (SPALTE1, SPALTE2, SPALTE3, SPALTE4)
primary key (SL)
);
Die Volltextsuche soll also mit "fulltext" realisiert werden. Bei der Suche nach einem Begriff werden dann die 4 Spalten (SPALTE 1 - 4) nach dem entsprechenden Eintrag durchsucht. Hier der Befehl:
select * from TABELLE where match (SPALTE1, SPALTE2, SPALTE3,
SPALTE4) against ('Suchbegriff');
Kann mir jemand weiter helfen wo hierbei ein Fehler ist? Die Suchergebnisse verhalten sich nämlich völlig unzuverlässig.
D.h. manche Suchbegriffe ergeben einen Treffer und manche eben nicht, obwohl beide vorhanden sind. Wird ein neuer Datensatz angelegt, so kommt es auch vor das urspünglich erfolgreiche Suchbegriffe eines alten Datensatzes plötzlich ebenfalls keine Treffer mehr ergeben.
Ist eine Suche nicht erfolgreich trotzdem der Begriff in den Daten vorhanden ist, so wird unter MySql folgende Meldung ausgegeben:
Empty set
Danke im vorraus um beste Grüße.
Simon
Hi!
Ich zitiere mal kurz aus der Doku (http://de.mysql.com/documentation/mysql/bychapter/manual.de_Reference.html#Fulltext_Search):
Solch eine Technik funktioniert am besten bei großen Textsammlungen (in der Tat wurde sie sorgfältig darauf optimiert). Bei sehr kleinen Tabellen spiegelt die Wortverteilung nicht adäquat seinen semantischen Wert wider, so dass dieses Modell manchmal bizarre Ergebnisse ergeben kann:
mysql> SELECT * FROM artikel WHERE MATCH (titel,artikeltext) AGAINST ('MySQL');
Empty set (0.00 sec)
Die Suche nach dem Wort MySQL erzeugt im obigen Beispiel keine Ergebnisse. Das Wort MySQL ist in mehr als der Hälfte der Zeilen vorhanden und wird deshalb als Stopword betrachtet (eins mit dem semantischen Wert 0). Das ist in der Tat das gewünschte Verhalten - eine natürlichsprachige Anfrage sollte bei einer 1 GB großen Tabelle nicht jede zweite Zeile zurückgeben.
Bei einem Wort, dass in der Hälfte der Zeilen in einer Tabelle übereinstimmt, ist es nicht sehr wahrscheinlich, dass relevante Dokumente gefunden werden, sondern statt dessen viele irrelevante Dokumente. Das kennen wir alle aus Recherchen über Suchmaschinen auf dem Internet. Das ist die Überlegung, die dahinter steht, dass solchen Wörtern ein niedriger semantischer Wert in diesem bestimmten Satz von Daten gegeben wird.
Vielleicht hilft es Dir ja!
Grüße
Andreas
Hi Simon,
Kann mir jemand weiter helfen wo hierbei ein Fehler ist?
Die Suchergebnisse verhalten sich nämlich völlig unzuverlässig.
Du hast offenbar eine Diskrepanz zwischen Deiner Suchfunktion und Deinen Ergebnissen.
Was von beiden möchtest Du lieber an das andere anpassen? ;-)
Der Wort-Indexer von mySQL arbeitet mit diversen Konfigurationswerten, die Du am besten dem mySQL-Quelltext entnehmen kannst (richtig konfigurierbar wird das erst in mySQL 4.x).
Ich poste Dir mal ein Stück aus einer Dokumentation von etwas, das ich basierend auf diesem FULLTEXT gebaut habe ... ach ja, es gibt auch noch eine Definition von Wort-Delimiter-Zeichen (ein wordchars-Makro), die Du auch noch verstanden haben mußt (oder anpassen solltest - mir gefiel sie hinreichend gut).
Wenn man die Kristallkugel-Logik des FULLTEXT-Treibers mal verstanden und "zugeritten" hat, dann ist er prima. ;-)
Viele Grüße
Michael
mySQL nimmt in seine Volltext-Indexbäume standardmäßig nur Worte mit einer Länge von _mindestens_4_Zeichen_ auf.
...
Diese Eigenschaft des FULLTEXT-Index der myISAM-Tabellen von mySQL wird durch die Konstante MIN_WORD_LEN in der Datei myisam/ftdefs.h der mySQL-Quelltext-Distribution festgelegt.
Ich habe den dort definierten Wert von 4 auf 3 geändert, den mySQL-Datenbanktreiber neu übersetzt und den Volltextindex neu aufgebaut. Durch die nun zusätzlich geindexten Worte mit genau 3 Zeichen nahm das Volumen der Indexbaumdatei um 15% zu - das ist vertretbar.
Eine merkliche Beeinträchtigung der Suchgeschwindigkeit war nicht feststellbar; genaue Messungen wurden hierfür allerdings auch nicht vorgenommen.
Der mySQL-Indexer nimmt _nicht_ jedes Wort, das er bei der Zerlegung eines Textes isoliert hat, in den entsprechenden Volltextindex auf.
Sofern dies im Quelltext aktiviert ist (bei mySQL 3.23.47 ist das standardmäßig der Fall), verwendet der Indexer eine _Stopwortliste_ häufiger, aber wenig aussagekräftiger Worte, welche beim Aufbau des Indexbaums ignoriert werden sollen.
Diese Liste ist in der Datei myisam/ft_static.c der mySQL-Quelltext-Distribution als String-Array definiert und enthält in der Standardauslieferung 570 solcher Worte - überwiegend englische Begriffe, aber auch einige wenige deutsche und französische Worte.
Ich habe mir ein eigenes kleines Perl-Programm geschrieben und für einen Testdatenbestand von ... eine Wortverteilungstabelle erstellt. Von den 5% häufigsten Worten habe ich diejenigen, welche mir ähnlich wenig aussagekräftig erschienen wie die bereits in der Stopwortliste enthaltenen Begriffe, isoliert und beide Listen zusammengemischt; außerdem habe ich alle Stopworte mit weniger als drei Buchstaben (die aufgrund der von mir eingestellten erforderlichen Mindestlänge ohnehin keinen Effekt haben werden) aus der Liste gelöscht (damit der Volltextindexer sie nicht unnötigerweise trotzdem prüfen muß).
Die daraus entstandene Stopwortliste enthält nun 873 Begriffe.
Auch für diese Änderung mußte der mySQL-Datenbanktreiber neu übersetzt und der Volltextindex neu aufgebaut werden.