Sphinx: Suche ohne Rätsel
Artikel erschienen in Swiss IT Magazine 2007/09
Zu den wichtigsten Bestandteilen von Webapplikationen oder Online-Angeboten gehört eine gute Suchmaschine. Doch wer nicht gerade Google für sich suchen lassen möchte, hat keine allzu einfache Aufgabe vor sich. Denn die wenigsten der freien Datenbanken bringen leistungsfähige Werkzeuge zur Volltextsuche mit. So unterliegt beispielsweise die Volltextsuche von MySQL, die eine der bekannteren ist, etlichen Restriktionen:
- Sie kann nur mit der Storage Engine MyISAM eingesetzt werden.
So bietet sich der Einsatz von separaten Werkzeugen an, die auf Volltextsuche und grosse Textmengen spezialisiert sind. Das wohl beste freie Werkzeug ist das Java-Framework Lucene, das wir im Rahmen unserer Apache-Serie in InfoWeek 18/2006 bereits vorgestellt haben. Allerdings ist Lucene nicht ganz einfach zu bedienen und als Java-Software nicht unbedingt ideal für die Verwendung mit anderen Sprachen, sofern nicht eine einigermassen gleichwertige Implementierung existiert. Weniger ausgefeilt, dafür einfacher zu bedienen, ist Sphinx (www.sphinxsearch.com).
Sphinx (SQL Phrase Index) steht unter der GPL und läuft auf so ziemlich jedem unixoiden Betriebssystem, auf dem ein C++-Compiler wie g++ vorhanden ist. Windows wird ebenfalls unterstützt, unterliegt aber einigen Einschränkungen.
Sphinx ist grundsätzlich ein relativ einfach aufgebautes Werkzeug. Es besteht aus einem Indexer, der sich um das Indizieren der Datenbestände kümmert, dem Daemon searchd, der die Suchanfragen beantwortet, und dem Kommandozeilenwerkzeug search, das einem eine einfache Möglichkeit bietet, um Suchanfragen an den Sphinx-Daemon zu stellen.
Das Verhalten von Indexer und searchd wird über die zentrale Konfigurationsdatei sphinx.conf geregelt. In ihr werden nicht nur die Datenquellen für den Indexer konfiguriert, sondern unter anderem auch das Stemming oder die zu verwendenden Listen mit Stopwörtern eingestellt.
Sphinx arbeitet mit strukturierten Dokumenten und damit ähnlich wie eine Datenbank, bei der ein Dokument quasi einem Datensatz entspricht, der aus verschiedenen Feldern aufgebaut ist. Dabei wird zwischen Feldern, die indiziert werden, und Attributen unterschieden. Die Attribute dienen dazu, zusätzliche Informationen zu den Datensätzen zu speichern, die zum Einschränken der Suchresultate oder zu deren Sortierung genutzt werden können. Allerdings können Attribute im Moment nur als 32bittige Integer (vorzeichenlos) und UNIX-Timestamps verwendet werden, was aber für die meisten Anwendungen reichen dürfte.
Die Indices werden losgelöst von den eigentlichen Daten in mehreren separaten Dateien auf Disk gespeichert. So ist es problemlos möglich, Daten aus verschiedenen Quellen in denselben Index zu integrieren, sofern sie alle gleich strukturiert sind. Als Datenquellen können im Moment nicht nur die relationalen Datenbanksysteme MySQL und PostgreSQL verwendet werden, die über ihre regulären Client-APIs angesprochen werden, sondern alle Arten von Dateien und sogar nicht unterstützte Datenbanken. Für Dateien sowie nicht direkt unterstützte Datenbanken muss man allerdings den Weg über XML gehen, indem man von den einzelnen Datensätzen, die indiziert werden sollen, XML-Dokumente erstellt und sie an das Sphinx-Programm XMLpipe weitergibt. Allerdings ist XMLpipe im Moment noch auf ein bestimmtes XML-Schema beschränkt, an das man sich halten muss, selbst wenn es die gewünschten Funktionen zur Filterung oder Gruppierung von Suchresultaten nur unzureichend abbildet.
Im Falle von MySQL und PostgreSQL werden von Sphinx die Daten wie von einem regulären Client-Programm mit SQL abgefragt. Die Query kann frei gestaltet werden und ermöglicht so beispielsweise, auch komplizierte Berechnungen auszuführen oder Daten aus Views abzufragen, was beispielsweise bei der Volltextsuche von MySQL nicht möglich ist. Welche Daten als Volltextfelder und welche als Attribute behandelt werden sollen, wird per Konfigurationsdirektive geregelt. Es müssen dabei nur zwei Dinge beachtet werden: Jeder Datensatz muss über eine eindeutige ID verfügen, die in einen 32bittigen vorzeichenlosen Integer passt, und es dürfen nicht mehr als 32 Volltextfelder dem Indexer zugeführt werden.
Damit die Indizierung die Datenquellen nicht zu stark belastet, kann Sphinx so konfiguriert werden, dass es die Quellen Schritt für Schritt abfragt, beispielsweise in 100er- oder 1000er- Schritten.
Gesucht werden kann, wie bereits erwähnt, entweder über die Kommandozeile mit dem Werkzeug search oder mit Hilfe des Daemons searchd, mit dem über ein Binärprotokoll kommuniziert werden kann. Passende APIs sind unter anderem für PHP, Python, Perl und Ruby vorhanden und können relativ einfach für weitere Sprachen erstellt werden. Eine weitere Möglichkeit ist die Nutzung der Sphinx Storage Engine für MySQL, die selber zwar keine Daten speichert, aber ein Interface in Form einer herkömmlichen Datenbank-Tabelle zum searchd bietet. So ist die Suche für Sprachen einfacher, für die kein Sphinx-API zur Verfügung steht, die aber auf MySQL zugreifen können. Zudem lassen sich weitere Operationen wie JOINs bei der Abfrage der Resultate ausführen.
Findet Sphinx passende Datensätze, werden diese auf der Kommandozeile komplett zurückgeliefert, also auch inklusive Feldern, die ursprünglich nicht zur Erzeugung der Indices verwendet wurden. Wer über die APIs zugreift, muss selber die passenden Daten aus den Quellen fischen. Eine Filterung der Resultate ist mit Hilfe der Attribute möglich, ebenso wie eine Beschränkung der zurückgelieferten Datensätze mit einem variablen Versatz, sodass sich die Suchresultate problemlos auf mehrere Seiten verteilen lassen. Die Sortierung der gefundenen Datensätze ist nach Relevanz, Attributen und Zeit möglich. Zudem können Sortierungsinstruktionen vergleichbar zu SQL zusammengehängt werden («feld1 DESC, feld2 ASC»).
Sollte man mit besonders grossen Indices operieren oder die Suchgeschwindigkeit einem nicht ausreichen, kann man die Arbeit problemlos auf mehrere Rechner verteilen. searchd verteilt dann die Anfragen an die Sphinx-Daemons auf den verschiedenen Rechnern, fasst darauf die erhaltenen Resultate zusammen, wobei Doubletten automatisch entfernt werden, und liefert schliesslich das aggregierte Resultat-Set zurück.
Aufbau von Sphinx