Query-Logik von Parametern trennen mit Mustache-Templates
Wird die vollständige Elasticsearch Query DSL direkt im Anwendungscode zusammengebaut, verteilt sich Suchlogik über viele Stellen der Codebasis und jede Anpassung an einer zentralen Query erfordert Änderungen an mehreren Orten gleichzeitig. Search Templates lösen dieses Problem, indem sie eine Mustache-basierte Query-Vorlage einmal zentral in Elasticsearch hinterlegen und der Anwendungscode anschließend nur noch benannte Parameter übergibt, ohne selbst eine Zeile Query-DSL zu kennen. Damit wandert die eigentliche Suchlogik dorthin, wo sie technisch verwaltet werden sollte, und Anwendungsentwickler arbeiten mit einer stabilen, klar dokumentierten Schnittstelle. Wie Search Templates aufgebaut sind, welche Vorteile das für die Zusammenarbeit zwischen Suchteam und Anwendungsteam bringt und wie eine parametrisierte Produktsuche damit konkret aussieht, zeigt dieser Artikel.
Inhaltsverzeichnis
- 1. Das Grundproblem: verstreute Query-Logik im Anwendungscode
- 2. Mustache-Syntax: wie Platzhalter in der Query DSL funktionieren
- 3. Ein Search Template über die _scripts-API anlegen
- 4. Ein Search Template ausführen
- 5. Vorteile für Anwendungsentwickler: keine Query-DSL im Anwendungscode
- 6. Versionierung und kontrollierte Änderungen an Templates
- 7. Performance: Kompilierung und Caching von Templates
- 8. Praxisbeispiel: parametrisierte Produktsuche mit Standardwerten
- 9. Fallstricke und Empfehlungen für den produktiven Einsatz
- 10. Zusammenfassung
- 11. FAQ
1. Das Grundproblem: verstreute Query-Logik im Anwendungscode
In vielen gewachsenen Anwendungen findet sich dieselbe oder eine sehr ähnliche Query-DSL-Struktur mehrfach im Code wieder, einmal für die Produktsuche im Frontend, einmal für einen internen Suchdienst und einmal für einen Batch-Export, jeweils mit kleinen Abweichungen. Ändert sich die zugrunde liegende Relevanzstrategie, etwa weil ein zusätzliches Boosting für aktuelle Angebote eingeführt wird, müssen alle diese Stellen einzeln gefunden und konsistent angepasst werden, was in der Praxis regelmäßig zu Inkonsistenzen führt.
Search Templates verschieben die eigentliche Query-Struktur aus dem Anwendungscode in eine zentral in Elasticsearch verwaltete Vorlage. Die Anwendung ruft diese Vorlage über ihren Namen auf und übergibt lediglich die konkreten Suchparameter, während die komplette Struktur der Query, inklusive Boosting-Regeln, Filtern und Sortierung, an einer einzigen Stelle gepflegt wird.
2. Mustache-Syntax: wie Platzhalter in der Query DSL funktionieren
Ein Search Template ist im Kern eine reguläre Query-DSL-Struktur, in der einzelne Werte durch Mustache-Platzhalter wie {{suchbegriff}} ersetzt werden. Beim Ausführen des Templates ersetzt Elasticsearch jeden Platzhalter durch den übergebenen Parameterwert und wertet die daraus entstandene, vollständige Query genau wie eine normale Suchanfrage aus. Mustache unterstützt dabei auch bedingte Blöcke über {{#parameter}}...{{/parameter}}, die einen Query-Bestandteil nur einfügen, wenn der entsprechende Parameter tatsächlich übergeben wurde.
Diese bedingten Blöcke sind besonders wertvoll für optionale Filter: Ein Preisfilter soll nur dann in die Query eingebaut werden, wenn der Nutzer tatsächlich eine Preisspanne ausgewählt hat, andernfalls soll die Query ohne diesen Filterbestandteil laufen. Ohne Mustache-Bedingungen müsste die Anwendung selbst mehrere Varianten der Query zusammenbauen, mit Mustache genügt ein einziges Template für alle Kombinationen gesetzter und nicht gesetzter Parameter.
3. Ein Search Template über die _scripts-API anlegen
Search Templates werden über die _scripts-API gespeichert, dieselbe API, die auch für andere gespeicherte Skripte verwendet wird. Jedes Template erhält einen eindeutigen Namen, unter dem es später referenziert wird, und einen source-Block mit der eigentlichen Query-DSL-Struktur inklusive Mustache-Platzhaltern. Optional lässt sich auch ein params-Block mit Standardwerten hinterlegen, der greift, sobald die Anwendung einen bestimmten Parameter beim Aufruf nicht übergibt.
Diese zentrale Speicherung hat einen praktischen Nebeneffekt: Eine Änderung am Template wirkt sich sofort auf alle Anwendungen aus, die dieses Template referenzieren, ohne dass irgendeine dieser Anwendungen neu deployt werden müsste. Für Relevanz-Tuning, das häufiger iteriert wird als der eigentliche Anwendungscode, ist das ein erheblicher Geschwindigkeitsvorteil.
PUT _scripts/produktsuche_standard
{
"script": {
"lang": "mustache",
"source": {
"query": {
"bool": {
"must": [
{ "multi_match": { "query": "{{suchbegriff}}", "fields": ["name^3", "beschreibung"] } }
],
"filter": [
{{#kategorie}}{ "term": { "kategorie": "{{kategorie}}" } },{{/kategorie}}
{ "range": { "preis": { "gte": "{{preis_min}}{{^preis_min}}0{{/preis_min}}", "lte": "{{preis_max}}{{^preis_max}}100000{{/preis_max}}" } } }
]
}
},
"size": "{{anzahl}}{{^anzahl}}20{{/anzahl}}"
},
"params": { "anzahl": 20 }
}
}
4. Ein Search Template ausführen
Ausgeführt wird ein gespeichertes Template über den Endpunkt _search/template, wobei die Anwendung lediglich den id-Verweis auf das gespeicherte Template und ein params-Objekt mit den konkreten Werten übergibt. Die Antwort entspricht exakt der Antwort einer regulären Suchanfrage, sodass sich vorhandener Antwort-Verarbeitungscode ohne Anpassung weiterverwenden lässt.
Für die lokale Entwicklung und zum Debugging eignet sich der Endpunkt _render/template, der ein Template mit gegebenen Parametern lediglich auflöst und die daraus entstehende, vollständige Query DSL zurückliefert, ohne tatsächlich eine Suche auszuführen. Damit lässt sich schnell prüfen, ob ein Template mit bestimmten Parametern die erwartete Query erzeugt, bevor man es produktiv gegen den Index laufen lässt.
GET /produkte/_search/template
{
"id": "produktsuche_standard",
"params": {
"suchbegriff": "akkuschrauber",
"kategorie": "werkzeuge",
"preis_max": 89.90
}
}
5. Vorteile für Anwendungsentwickler: keine Query-DSL im Anwendungscode
Für Teams, die eine Suchschnittstelle für andere Anwendungsteams bereitstellen, bedeutet ein Search Template eine klare Verantwortungstrennung: Das Such- oder Datenteam pflegt Relevanz, Boosting und Filterlogik zentral im Template, während Anwendungsentwickler nur eine benannte, dokumentierte Parameterliste kennen müssen, etwa Suchbegriff, Kategorie und Preisspanne. Änderungen an der Relevanzstrategie erfordern damit keine Abstimmung mit jedem einzelnen Anwendungsteam mehr, solange sich die Parameterschnittstelle nicht ändert.
Das reduziert auch das Risiko fehlerhafter Query-DSL-Konstruktion in Anwendungscode, der typischerweise nicht auf Elasticsearch-Query-Syntax spezialisiert ist. Statt verschachtelter bool-Strukturen im Anwendungscode zu debuggen, reicht ein Blick in das zentrale Template, das von den Personen gepflegt wird, die sich mit der Query DSL tatsächlich auskennen.
6. Versionierung und kontrollierte Änderungen an Templates
Da Änderungen an einem Search Template sofort und ohne Deployment für alle aufrufenden Anwendungen wirksam werden, empfiehlt sich eine bewusste Versionierungsstrategie über den Template-Namen selbst, etwa produktsuche_v2 statt einer direkten Überschreibung von produktsuche_standard. So können neue Anwendungsversionen gezielt auf die neue Template-Version umschalten, während bestehende Aufrufer unverändert weiterarbeiten, bis sie explizit migriert werden.
Für kontrollierte Rollouts eignet sich außerdem ein A/B-Testing-Ansatz, bei dem ein Teil des Traffics testweise gegen ein neues Template geleitet wird, während die Mehrheit weiterhin das bewährte Template nutzt. Da beide Templates unabhängig in _scripts gespeichert sind, lässt sich dieser Ansatz ohne Anwendungscode-Änderung rein über die aufgerufene Template-ID steuern.
7. Performance: Kompilierung und Caching von Templates
Elasticsearch kompiliert ein gespeichertes Template beim ersten Aufruf und hält die kompilierte Form in einem internen Skript-Cache vor, sodass wiederholte Aufrufe desselben Templates keine erneute Mustache-Kompilierung erfordern. Der eigentliche Ausführungsaufwand eines Search Templates unterscheidet sich dadurch praktisch nicht von einer direkt formulierten, äquivalenten Query, der Zusatzaufwand beschränkt sich auf die einmalige Parametersubstitution pro Aufruf.
Bei sehr komplexen Templates mit vielen bedingten Blöcken und tief verschachtelter Logik lohnt sich dennoch ein Blick auf die Größe des Skript-Caches, insbesondere wenn viele unterschiedliche Templates parallel im Einsatz sind. Der Cache lässt sich über script.cache.max_size anpassen, falls häufig genutzte Templates aus dem Cache verdrängt werden und dadurch wiederholt neu kompiliert werden müssen.
8. Praxisbeispiel: parametrisierte Produktsuche mit Standardwerten
Im gezeigten Template für die Produktsuche wird der Suchbegriff verpflichtend über multi_match gegen Name und Beschreibung geprüft, während Kategorie und Preisspanne optional bleiben. Fehlt der Preisfilter komplett, greifen über die Mustache-Negationssyntax {{^preis_min}} sinnvolle Standardwerte, sodass die Query auch ohne explizite Preisangabe eine gültige, sinnvolle Bereichsbedingung enthält, statt mit einem leeren oder fehlerhaften Filter zu scheitern.
Die Anwendung selbst muss lediglich die vom Nutzer eingegebenen Werte als Parameter durchreichen, ohne zu wissen, dass im Hintergrund eine bool-Query mit multi_match, bedingtem term-Filter und range-Filter aufgebaut wird. Diese Trennung bleibt auch dann stabil, wenn das Suchteam später etwa ein zusätzliches Function-Score-Boosting für Lagerbestand einbaut, solange sich die Parameterschnittstelle nicht ändert.
9. Fallstricke und Empfehlungen für den produktiven Einsatz
Ein häufiger Fehler ist, Parameter ungeprüft und ohne Escaping in ein Template einzusetzen, insbesondere bei Freitextfeldern, die theoretisch Mustache-Sonderzeichen enthalten könnten. Elasticsearch escaped Parameterwerte innerhalb von Mustache-Ausdrücken standardmäßig korrekt, problematisch wird es nur, wenn Parameter versehentlich direkt als Rohquery statt als Wert eingesetzt werden, was die Grenze zwischen Parametrisierung und potenzieller Query-Injection verwischen kann.
Empfehlenswert ist außerdem, jedes produktive Template mit einer kleinen Testsuite aus _render/template-Aufrufen abzusichern, die typische und Grenzfälle der Parameterkombination abdeckt, etwa fehlende optionale Parameter, extreme Preisspannen oder leere Suchbegriffe. So lassen sich Regressionen bei Template-Änderungen frühzeitig erkennen, bevor sie produktiv bei echten Suchanfragen auffallen.
| Aspekt | Query DSL im Anwendungscode | Search Template | Praxisrelevanz |
|---|---|---|---|
| Pflegeort der Query-Logik | Verteilt über Codebasen | Zentral in _scripts | Templates verhindern Inkonsistenzen |
| Deployment bei Änderungen | Neues Anwendungsdeployment nötig | Sofort wirksam ohne Deployment | Schnellere Relevanz-Iteration |
| Fachwissen im Anwendungscode | Query-DSL-Kenntnis erforderlich | Nur benannte Parameter nötig | Klare Trennung der Verantwortung |
| Debugging | Über Anwendungslogs | Über _render/template direkt prüfbar | Schnellere Fehlersuche bei Templates |
| Optionale Filter | Manuelle Fallunterscheidung im Code | Mustache-Bedingungsblöcke | Ein Template für alle Parameterkombinationen |
Mironsoft
Suchindex-Setup, Relevanz-Tuning und Magento-Suche
Magento-Suche, die die falschen Produkte zuerst zeigt?
Wir richten Elasticsearch oder OpenSearch für Magento sauber ein, tunen Relevanz und Facetten auf das tatsächliche Sortiment und optimieren Indexierungsprozesse für große Kataloge.
Relevanz-Tuning
Suchergebnisse und Facetten auf die tatsächlichen Kundenbedürfnisse abstimmen.
Such-Migration
Umstieg von Solr oder MySQL-Suche auf Elasticsearch/OpenSearch sauber begleiten.
Index-Performance
Indexierungsprozesse für große Kataloge zuverlässig und performant gestalten.
10. Zusammenfassung
Search Templates: Das Wichtigste auf einen Blick
Grundprinzip
Search Templates trennen die Mustache-basierte Query-DSL-Struktur von den konkreten Suchparametern, die eine Anwendung nur noch benannt übergibt.
Verwaltung
Templates werden über die _scripts-API zentral gespeichert und über _search/template mit Parametern ausgeführt, ohne Anwendungscode-Änderung bei Query-Anpassungen.
Vorteil für Teams
Anwendungsentwickler kennen nur eine dokumentierte Parameterschnittstelle, während das Suchteam Relevanz und Filterlogik unabhängig weiterentwickelt.
Praxisbeispiel
Eine parametrisierte Produktsuche mit optionalem Kategorie- und Preisfilter zeigt, wie Mustache-Bedingungsblöcke ein einziges Template für alle Parameterkombinationen tragfähig machen.