UX Audit

Wir trainieren dein Team? Buch unsere Workshops, Trainings und Coachings.

Zeigt her!
Close

Laravel: Performante Suche

31. Juli 2018, von Daniel
vom Suchen und Finden

Bei unseren großen Projekten haben wir hauptsächlich Symfony- und Laravel Komponenten im Einsatz, erweitern den Kern um die spezifischen Anforderungen abzudecken und bauen dann ein Modul-Management darüber, um Erweiterbarkeit zu gewährleisten.

Beim Aufsetzen des Kerns bin ich immer wieder auf den Use-Case gestoßen, dass Daten aus unterschiedlichsten Tabellen irgendwo im System zentral benötigt werden. Das einfachste Beispiel dafür ist eine zentrale Suche, welche verschiedenste Inhaltstypen durchsucht. In diesem Beitrag werde ich euch erklären, wie einfach es ist, so eine Suche in Laravel zu integrieren.

Als Entwickler sucht man gewöhnlich immer nach fertigen Packages, bevor man selbst einen Finger rührt. Das habe ich in diesem Fall natürlich auch gemacht, und bin auf “Laravel Scout” — die hauseigene Suche von Laravel — gestoßen. Für unser Projekt ist das Package aber nicht gut geeignet, da unsere Datenstruktur & unser Ranking zu komplex ist. Keine Sorge: in diesem Beitrag konzentriere ich mich auf die Basics, um den Rahmen nicht zu sprengen 😉

Nach kurzem Grübeln war schnell mal klar:
Um die Suche performant zu halten, muss eine neue Datenbanktabelle angelegt werden, welche bei Suchen abgefragt wird.

Sollte es diese nämlich nicht geben, müssten alle Tabellen, welche durchsuchbar sind, einzeln abgefragt werden!! Das wäre für die Performance natürlich ein No-Go!

Im einfachsten Fall reicht eine Tabelle mit folgenden Spalten:

  • Suchtext: nach dem Text wird bei Abfragen gesucht
  • Inhaltstyp-Klasse: damit beim Ergebnis der richtige Inhaltstyp geladen werden kann
  • Inhalts-ID: die ID des Inhaltselements

Diese Tabelle soll beim Erstellen, Updaten und Löschen von durchsuchbaren Inhalten automatisch geupdatet werden.

Laravel erweitern & Models vorbereiten

Für diesen Schritt wird ein “Manager” benötigt, welcher alle durchsuchbaren Inhalte überwacht, und bei bestimmten Events die Suchtabelle updatet. Ich werde den Manager in den nächsten Zeilen einfach “Search-Engine” oder “Suchmaschine” nennen.

Laravel bietet die einfache Möglichkeit, das System mit sogenannten Service-Providern zu erweitern. Ein solcher muss erstellt werden, um darin die Search-Engine zu instanzieren. Dann braucht die Suchmaschine noch die Information, welche Models durchsuchbar sind. Wie sie zu dieser Information kommt ist eigentlich egal. In kleinen Projekten löse ich das über ein config-Array, welches alle Klassen enthält. Bei großen Projekten überlasse ich diesen Task dem Modul-Management, um auch Inhalte aus Modulen für die Suche bereitzustellen.

Um sicherzustellen, dass die Inhalte korrekte Daten für die Suchtabelle zur Verfügung stellen, und bei einem Such-Request die richtigen Daten zurückgeben, verpflichte ich diese, ein Searchable Interface implementieren.

Ein einfaches Beispiel dafür wäre:

interface Searchable {
    public function searchFields(): array;
    public function searchResult(); array;
}

Damit ist sichergestellt, dass alle durchsuchbaren Models angeben, welche Felder bei der Suche berücksichtigt werden. Außerdem muss das Model auch definieren, welche Daten als Suchergebnis zurückgegeben werden.

Somit sind die Models für die Suche vorbereitet.

Suchtabelle aktuell halten

Hier kommt Laravel’s Event-System zum Einsatz. Ein mächtiges Instrument, welches einem die Arbeit um ein Vielfaches erleichtert! Eloquent (Laravels ORM — Object-relational mapping) bietet bereits viele vordefinierte Events für Models. Wenn man auf mehrere Events eines Models reagieren will, kann man sogenannte “Event-Observer” registrieren. Wenn ein Model-Event auftritt, wird dann die gleichnamige Methode des Observers aufgerufen.

Das bedeutet, wenn auf das “created” Event reagiert werden soll, muss im Observer stets eine Methode namens “created” implementiert werden. Alle Event-Methoden bekommen das jeweilige Model als Parameter übergeben. Da alle Models das Searchable Interface implementieren, kann als Argumenttyp-Deklaration “Searchable” angegeben werden.

Um die Inhalte der Suchtabelle aktuell zu halten, muss für alle Searchables auf die Events “saved” und “deleted” reagiert werden. Der Observer muss sich dann nur darum kümmern, dass beim “saved”-Event ein Eintrag erstellt beziehungsweise upgedatet wird, und beim “deleted” die jeweiligen Einträge aus der Suchtabelle gelöscht werden.

Um das zu arrangieren, muss die Search-Engine über alle registrierten Searchable-Klassen iterieren und jeweils die statische Methode “observe” ausführen, um für das Model einen Event-Observer zu registrieren:

foreach ($searchableClasses as $searchableClass) {
    // hier prüfen, ob $searchableClass das Interface implementiert!
    $searchableClass::observe(SearchObserver::class);
}

Ergebnisse Finden

Um nun zu Suchergebnissen zu kommen, muss jetzt einfach nur die Suchtabelle nach einem bestimmten Text abgefragt werden:

SELECT model_class, model_id
FROM search_table
WHERE search_text
LIKE “%danach wird gesucht%”;

Diese Abfrage gibt alle Ergebnisse von allen durchsuchbaren Inhaltstypen zurück. Dann muss nur noch die model_id von der model_class laden.

$content = $modelClass::find($model_id);

Der Inhalt sollte dann existieren, da beim Löschen ja auch der Inhalt aus der Suchtabelle gelöscht wird; aber um sicherzugehen, kann geprüft werden, ob $content eine Instanz von $modelClass ist.

Andere Use-Cases

Der Einsatz von Event-Observer in Kombination mit einem “DataManager” erweist sich auch in zahlreichen anderen Anwendungsgebieten als äußerst hilfreich. Wir haben beispielsweise ein Reporting-System, welches diverse Events speichert und Statistiken auswertet, auf Basis dieses Konzepts aufgebaut. In diesem Fall waren jedoch einige Custom-Events im Einsatz (nicht nur die default Eloquent Events). Ein weiterer Anwendungsfall, welcher mir spontan dazu einfällt, wäre ein Notification-Center.

Du willst mit jemanden über das Thema plaudern?

Einen kostenlosen Termin mit CEO Susanne vereinbaren!

Daniel

Meine Rolle bei Liechtenecker: Backend Development🤓 Wenn es weder IT noch Digitalisierung gäbe, wäre mein Beruf: Musiker Mein Herz schlägt für: PHP Development, Progressive Metal, Kaffee
Keine Kommentare vorhanden.
Kommentar verfassen
Name
Mail
Web
Captcha
Erfolgreich!
Fehler!
Technologie – Blogbeitrag

Generative AI: Eine Web-App in 50 Bahn-Kilometern

18. April 2024, von stephan

Es ist früher Donnerstagabend am Wiener Franz-Josefs-Bahnhof. Schwärme an Pendlern strömen in die Züge. Die Menschen wirken erschöpft und müde. Viele nutzen die Zeit im Zug um ein Buch zu lesen oder einfach nur aus dem Fenster zu schauen. Die Zugfahrt nach dem Büro ist für mich meistens die Zeit, offene Tasks abzuschließen, Tickets zu verschieben und zu kommentieren oder E-Mails zu beantworten. Doch heute soll das anders sein.

Jetzt lesen
Liechtenecker Leseliste #62 mit Susanne Liechtenecker
Inspiration – Podcasts

Folge #62 mit Susanne Liechtenecker

27. November 2020

In Folge 62 besinnt sich Susanne auf die Anfänge dieses Podcasts und begrüßt keinen Gast, sondern erzählt über das Buch "Jäger, Hirten, Kritiker" von Richard David Precht und warum es sie inspiriert hat.

Jetzt anhören
Close