knuspermagier.de
Der privateste Blog von Philipp.

Volltext-Suche mit Redis

Einer meiner Punkte auf der Todo-Liste für Blogchain war natürlich auch eine Suche. Ständig suchte ich im Wordpress-Blog nach Dingen, die ich irgendwann mal geschrieben habe. Auf dieses Feature verzichten kam also nicht in Frage!

Doch wie?

  1. Die “Viel zu viel Zeit”-Lösung: Einfach komplett selber bauen
  2. Die “Zu viel Zeit und komplett verrückt”-Lösung: Elastic Search aufsetzen
  3. Die “Könnte gerade richtig sein”-Lösung: RediSearch

Ab Version 4.0 unterstützt Redis, der Key-Value-Store meiner Wahl, der hier zum Beispiel auch alle Posts im Cache behält, Module. Eins ist zum Beispiel RediSearch, eine mit ziemlich vielen Features ausgestatte Volltext-Suche.

Wie leicht es war, das nun hier zu integrieren, können wir uns jetzt mal anschauen.

Redis 4.0 & Debian

Das erste Problem ist leider, dass Debian natürlich nicht mit Redis 4 shippt. Zum Glück ist Redis eine tolle Software ohne große Abhängigkeiten und lässt sich super einfach selbst kompilieren kein Problem. Ist das geschafft, installiert man noch das RediSearch Modul, ebenfalls schnell zusammenbauen. Eine Sache von fünf Minuten.

RediSearch-PHP

Nun kann man die Suche schon benutzen, aber die Redis-Befehle manuell zu benutzen ist natürlich mühsam. Zum Glück gibt es RediSearch-PHP. Kurz composer require ethanhann/redisearch-php ausgeführt und schon stehen uns ein paar tolle Klassen im Code zur Verfügung.

Anbindung

Der Dreh- und Angelpunkt ist der Index. Dort werden alle Daten abgelegt und er wird am Ende durchsucht. Statt jetzt ellenlange JSON- oder XML-Konfigurationsdateien anlegen zu müssen, kann man den Index schnell im Code erzeugen:

$postIndex = new Index($redis);

$postIndex->addTextField('title')
    ->addTextField('text')

try {
    $postIndex->info()
} catch(UnknownIndexNameException $e) {
    $postIndex->create();
}

Schon hat man einen Index, in den man jetzt Dokumente werfen kann, die title und text haben. Der try-catch-Block sorgt noch dafür, dass keine Fehlermeldung kommt, wenn man - aus Versehen - versucht einen Index doppelt anzulegen. Hinzufügen von Dingen ist nun ähnlich einfach:

$post = getPost(); // einen Post irgendwoher holen

$doc = $postIndex->makeDocument($post->id);
$doc->title->setValue($post->title);
$doc->text->setValue(strip_tags($post->text));

$index->replace($doc);

replace sorgt automatisch dafür, dass das Dokument im Index aktualisiert wird, falls es schon existiert. Zum Schluss nun das, worauf wir alle gewartet haben, die Suche!

$result = $index->search('Wurst');
var_dump($result->documents());

Das wars! Cool, oder?


Natürlich wäre es noch besser, wenn die Suche auch alte Posts aus dem Archiv findet. Darum kümmere ich mich vielleicht auch noch.


Ich bin froh, dass es neben ElasticSearch und all den anderen schwergewichtigen Lösungen mittlerweile auch RediSearch gibt. Es funktioniert und ist easy einzubauen und, soweit ich das beurteilen kann, zumindest für solche extrem kleinen Anwendungsfälle, wie ein Blog, ganz gut geeignet.

Als nächstes werde ich, glaube ich, versuchen, watched.li entsprechend zu erweitern. Die dumme Suche ist mir da schon lange ein Dorn im Auge und kann so sicherlich um einiges aufgewertet werden.