Erste Erfahrungen mit der Volltextsuche habe ich bereits mit MySQL 3 gesammelt. Ausgangspunkt war die Suche nach Textstellen in der Zitatedatenbank von
Aphorismen.de. Bis dahin hatte ich die übliche Suche nach Textinhalten mit LIKE "%suchtext%" genutzt. Bei ca. 80.000 Datensätzen dauerte die Suche bis zu einer Sekunde.
Beispiel:SELECT * FROM zitate WHERE text LIKE "%liebe%";
Das Anlegen eines Index nützt hier wenig, da durch den Einsatz des %-Zeichens zu beiden Seiten des Suchbegriffs kein Index benutzt wird. MySQL muß jedesmal die komplette Tabelle scannen. Bei wenig genutzten Datenbanken fällt die Sekunde nicht auf, aber wir hatten auf der Aphorismenseite damals schon mehrere tausend Besucher am Tag und bis zu 40 Datenbankabfragen pro Sekunde. Das brachte den Server häufig zum Stillstand.
Zudem brachte die LIKE Suchabfrage für meine Zwecke keine optimalen Suchergebnisse. Wenn jemand nach "Freund" gesucht hat, kamen auch Suchergebnisse die das Wort als Bestandteil enthielten also "Männerfreundschaft" etc.
Eine bessere Textsuche musste her. Doch die damalige Implementation der Volltextsuche in MySQL 3 war noch nicht ausgereift. Der Aufbau des Index dauerte mehr als 20 Minuten.
Richtig Spaß mach die Volltextfunktion erst ab MySQL Version 4. Die Performance ist auf unserem Server um den Faktor 100 höher als die normale Textsuche mit LIKE. Außerdem ist die Qualität der Suchergebnisse durch die Sortierung nach Relevanz erheblich gestiegen. Man kann ganze Gedichte als Suchbegriffe eingeben. Der Text in dem alle Suchwörter drin vorkommen wird als erstes Ergebnis angezeigt. Nebenbei ist dies auch eine Möglichkeit nach Doubletten zu suchen. Natürlich wird im Volltextmodus nach ganzen Wörtern gesucht, wie wir es von Google & Co. gewohnt sind.
Beispiel:SELECT * FROM zitate WHERE MATCH (text) AGAINST ('Liebe');
(Vorher sollte man natürlich einen Index vom Typ "fulltext" über eine oder mehrere Textspalten anlegen.) Allerdings fehlte mir noch eine deutsche Stoppwortliste.
MySQL wird bisher nur mit einer englischen Stoppwortliste geliefert. Stoppwörter sind "Rauschwörter". Ich würde sie als Verbindungswörter definieren, wie "und", "in", "der"... welche keinen Sinn machen in den Index mit aufzunehmen, da sich die eigentlichen Suchbegriffe nur verbinden und den Index unnötig aufblähen. Benutzt man die mitgelieferte englische Stoppwortliste dann werden die eigentlichen deutschen Rauschwörter mit in den Index aufgenommen während eine Suche nach "After eight" keine Suchergebnisse bringen würde, da beides englische Stoppwörter sind. Deshalb nutzen viele deutsche Webmaster erst gar keine Stoppwortliste.
Ich habe im Internet vergeblich nach einer deutschen Liste gesucht, aber keine gefunden. Deshalb habe ich eine eigene Stoppwortliste zusammengestellt. Allerdings war meine erste eigene Liste zu weitreichend. Eine Suche nach dem Text "Es gibt kaum etwas auf der Welt" bestand demnach bis auf das Wort "Welt" nur aus Stoppwörtern wodurch der Text mit 100%iger Übereinstimmung erst auf Rang 5 erschien denn andere Texte in denen das Wort "Welt" mehrfach vorkamen hatten eine höhere Relevanz. Deshalb musste ich die Stoppwortliste noch einmal überarbeiten. Wer Interesse hat, kann sie
hier downloaden.
Beispiel:SELECT * FROM zitate WHERE MATCH (text) AGAINST ('Es gibt kaum etwas auf der Welt');
Eingebunden wir die Stoppwortliste über einen Eintrag in der my.cnf.
Zum Beispiel:
ft_stopword_file="/usr/local/mysql/include/ft_stoptom.c
ft_min_word_len="3
Durch den Parameter ft_min_word_len="3" wird festgelegt, dass nur Wörter mit drei oder mehr Buchstaben in den Index aufgenommen werden. Das ist damit die kürzeste Wortlänge für eine Abfrage und beeinflusst auch die Größe des Index.
Der normale Volltextmodus ist der "Natural Language Search" Modus. Die Suchbegriffe werden dabei in Form eines Satzes eingegeben und MySQL bringt bei dieser Suche Ergebnisse, die mindestens eines der Suchwörter enthalten, d.h. eine Suche nach "heute ist ein schöner Tag" bringt am Ende der Ergebnisliste auch Texte in denen nur das Wort "Tag" vorkommt. Für unsere Suche nach Zitaten ist dieser Modus genau richtig, aber bei der Suche nach Autorennamen war er ungeeignet. Denn wenn ich nach dem Autor "Jean Paul" suche möchte ich nicht alle Autoren die "Jean" heißen und alle die "Paul" heißen, sondern nur den in dem beide Wörter vorkommen. Was ist, wenn ich bestimmte Wörter ausschließen möchte, oder nur die Ergebnisse haben will, die bestimmte Wörter definitiv enthalten?
Dann kann ich den Boolean Mode nutzen.
Beispiel:SELECT * FROM autoren WHERE MATCH (name) AGAINST ('+Jean +Paul -Klaus' IN BOOLEAN MODE);
Die Wörter Jean und Paul müssen vorkommen, das Wort Klaus darf nicht im Ergebnis enthalten sein. Die Anzahl der Suchergebnisse ist jetzt geringer als im "Natural Language" Mode, allerdings gibt es keine Sortierung nach Relevanz. (Ist eben boolean, gibt nur ja oder nein.) Für unsere Autorensuche passte der Boolean Modus gut. Aus der Sucheingabe extrahiere ich die einzelnen Wörter, entferne eventuell vorhandene Leerzeichen, füge den Wörtern ein "+" an den Anfang und führe eine Volltextsuche im Boolean Modus durch. Der Boolean Modus ist noch etwas schneller als der Natural Language Modus und funktioniert auch ohne Volltextindex.
Über ein Feedback und Hinweise zur Verbesserung der Stoppwortliste würde ich mich freuen.
©5.2005 - Thomas Schefter