Eigene Datenquellen ergänzen und die Performance bei schneller Eingabe im Griff behalten
Die Autocomplete-Vorschläge im Suchfeld wirken wie ein reines Frontend-Feature, entstehen aber vollständig serverseitig aus einer Reihe von DataProvidern. Dieser Artikel zeigt, wie diese Provider zusammenspielen, wie sich eine eigene Datenquelle wie CMS-Seiten ergänzen lässt und welche Stellschrauben tatsächlich beeinflussen, wie flüssig sich die Vorschläge bei schneller Eingabe anfühlen.
Inhaltsverzeichnis
- 1. Warum Autocomplete kein reines Frontend-Thema ist
- 2. Die DataProvider-Architektur im Überblick
- 3. Eigenen Provider für CMS-Seiten implementieren
- 4. Der GraphQL-Pfad für Storefronts ohne klassischen Autocomplete-Block
- 5. Server-seitiges Limit und Caching der Vorschläge
- 6. Debounce serverseitig gegenüber clientseitig abwägen
- 7. Mehrere Provider im gemeinsamen Performance-Budget
- 8. Messung und Monitoring der Autocomplete-Antwortzeit
- 9. Edge Cases und Abgrenzung zur Volltextsuche
- 10. Zusammenfassung
- 11. FAQ
1. Warum Autocomplete kein reines Frontend-Thema ist
Wer bei Autocomplete zuerst an Debounce-Timer und JavaScript denkt, übersieht die eigentliche Arbeit: Magento stellt die Vorschlagsliste bereits fertig sortiert und zusammengestellt auf dem Server bereit, das Frontend rendert lediglich, was der Server liefert. Die interessanten Stellschrauben, welche Datenquellen einfließen, wie viele Ergebnisse pro Quelle und in welcher Reihenfolge, liegen also im Backend.
Das unterscheidet dieses Thema klar von layered navigation oder allgemeinem Relevanz-Tuning der Volltextsuche, die bereits an anderer Stelle behandelt werden. Autocomplete läuft über einen eigenen, schlankeren Anfragepfad, der bewusst nicht den vollen Suchindex mit allen Aggregationen durchläuft, sondern auf schnelle Antwortzeiten optimiert ist.
Genau diese Optimierung auf Geschwindigkeit macht das Thema für Backend-Entwickler relevant: Jede zusätzliche Datenquelle, jedes zusätzliche Feld in der Ergebnisliste kostet Millisekunden, die sich bei jedem Tastendruck erneut summieren.
2. Die DataProvider-Architektur im Überblick
Der zentrale Einstiegspunkt ist Magento\Search\Model\Autocomplete, das eine Liste konfigurierter DataProvider durchläuft und deren Ergebnisse zu einer gemeinsamen Vorschlagsliste zusammenführt. Jeder Provider implementiert DataProviderInterface mit einer einzigen Methode getItems, die eine Liste von ItemInterface-Objekten liefert, typischerweise mit einem Titel und einer Ziel-URL.
Im Standardumfang sind zwei Provider aktiv: einer für Produktvorschläge, basierend auf dem Suchindex, und einer für populäre beziehungsweise zuletzt genutzte Suchbegriffe, basierend auf der search_query-Tabelle. Kategorien oder CMS-Seiten sind bewusst nicht Teil des Standards, wer diese Inhalte in den Vorschlägen sehen möchte, muss sie über einen eigenen Provider ergänzen.
Die Reihenfolge der Provider in der Konfiguration bestimmt direkt die Reihenfolge in der Vorschlagsliste, ein häufig übersehener Hebel, um beispielsweise Produktvorschläge bewusst vor populären Suchbegriffen anzuzeigen.
<type name="Magento\Search\Model\Autocomplete">
<arguments>
<argument name="dataProviders" xsi:type="array">
<item name="popularQueries" xsi:type="object">Magento\Search\Model\Autocomplete\DataProvider</item>
<item name="products" xsi:type="object">Magento\CatalogSearch\Model\Autocomplete\DataProvider</item>
<item name="cmsPages" xsi:type="object">Mironsoft\SearchAutocomplete\Model\Autocomplete\CmsPageDataProvider</item>
</argument>
</arguments>
</type>
3. Eigenen Provider für CMS-Seiten implementieren
Ein eigener Provider für CMS-Seiten folgt demselben Muster wie die eingebauten Provider: getItems liest den aktuellen Suchbegriff, filtert eine CMS-Page-Collection nach Titel und liefert eine begrenzte Anzahl Treffer als ItemInterface-Objekte zurück. Wichtig ist, die Collection explizit auf aktive, im aktuellen Store sichtbare Seiten einzuschränken, da CMS-Seiten anders als Produkte kein eigenes Sichtbarkeits-Attribut pro Kundengruppe kennen.
Die Ergebnisanzahl sollte klein gehalten werden, drei bis fünf Treffer reichen für eine Vorschlagsliste völlig aus. Eine ungefilterte LIKE-Abfrage über den gesamten CMS-Page-Titel-Index kann bei wachsender Seitenzahl spürbar langsamer werden als die bereits indexbasierte Produktsuche, weshalb sich ein einfacher Titel-Index über eine eigene Spalte lohnt, sobald mehr als wenige hundert Seiten gepflegt werden.
<?php
declare(strict_types=1);
namespace Mironsoft\SearchAutocomplete\Model\Autocomplete;
use Magento\Cms\Model\ResourceModel\Page\CollectionFactory;
use Magento\Search\Model\Autocomplete\DataProviderInterface;
use Magento\Search\Model\Autocomplete\ItemFactory;
use Magento\Search\Model\QueryFactory;
/**
* Liefert CMS-Seiten als zusätzliche Datenquelle für die Autocomplete-Vorschlagsliste.
*/
class CmsPageDataProvider implements DataProviderInterface
{
private const RESULT_LIMIT = 4;
/**
* @param CollectionFactory $collectionFactory
* @param ItemFactory $itemFactory
* @param QueryFactory $queryFactory
*/
public function __construct(
private readonly CollectionFactory $collectionFactory,
private readonly ItemFactory $itemFactory,
private readonly QueryFactory $queryFactory,
) {
}
/**
* Sucht aktive CMS-Seiten anhand des aktuellen Suchbegriffs und liefert sie als Vorschlags-Items.
*
* @return \Magento\Search\Model\Autocomplete\ItemInterface[]
*/
public function getItems(): array
{
$queryText = $this->queryFactory->get()->getQueryText();
$collection = $this->collectionFactory->create();
$collection->addFieldToFilter('is_active', ['eq' => 1])
->addFieldToFilter('title', ['like' => '%' . $queryText . '%'])
->setPageSize(self::RESULT_LIMIT);
$items = [];
foreach ($collection as $page) {
$items[] = $this->itemFactory->create(['title' => $page->getTitle()]);
}
return $items;
}
}
4. Der GraphQL-Pfad für Storefronts ohne klassischen Autocomplete-Block
Storefronts, die konsequent auf GraphQL setzen, rufen die Vorschläge nicht über den REST-nahen Autocomplete-Controller ab, sondern über eine products-Query mit reduzierter Feldauswahl, ergänzt um eine eigene, schlanke Query für CMS-Vorschläge. Das hat den Vorteil, dass sich Produkt- und CMS-Vorschläge in einer einzigen Anfrage bündeln lassen, statt zwei getrennte Requests bei jedem Tastendruck auszulösen.
Wichtig ist dabei, in der GraphQL-Query nur die tatsächlich für die Vorschlagsliste benötigten Felder abzufragen, also Name, URL-Key und ein kleines Bild, statt der vollen Produktdaten inklusive aller Attribute. Jedes zusätzliche Feld erhöht die Resolver-Zeit auf dem Server, was bei einer Funktion, die auf jeden Tastendruck reagiert, unmittelbar spürbar wird.
query AutocompleteSuggestions($search: String!) {
products(search: $search, pageSize: 5) {
items {
name
url_key
small_image {
url
}
}
}
}
5. Server-seitiges Limit und Caching der Vorschläge
Die Anzahl der Vorschläge pro Anfrage wird über den Konfigurationspfad catalog/search/autocomplete_limit gesteuert und wirkt sich direkt auf die Antwortzeit aus, weil jeder zusätzliche Treffer eine zusätzliche Datenbank- beziehungsweise Indexoperation bedeutet. Ein Limit von fünf bis acht Ergebnissen ist in der Praxis für die meisten Shops ausreichend und deutlich schneller als zwanzig oder mehr Treffer.
Da das Kundenkonto über private content läuft, Autocomplete-Anfragen aber unabhängig vom eingeloggten Zustand meist dieselben Daten liefern, lohnt sich ein kurzes, wenige Sekunden gültiges HTTP-Caching der Antwort auf Ebene des Full-Page-Cache oder eines vorgeschalteten Reverse-Proxys, insbesondere für die häufigsten Suchbegriffe, die ohnehin nahezu identisch bleiben.
6. Debounce serverseitig gegenüber clientseitig abwägen
Clientseitiges Debounce, also das Verzögern der Anfrage um typischerweise zweihundert bis dreihundert Millisekunden nach dem letzten Tastendruck, reduziert die Zahl der Requests, die überhaupt beim Server ankommen. Das ist der wirksamste einzelne Hebel, denn jede vermiedene Anfrage spart vollständig deren Serverzeit, während serverseitige Optimierungen die verbleibenden Anfragen nur schneller, nicht aber weniger machen.
Serverseitig lässt sich ergänzend eine einfache Anfrage-Drosselung pro Session einbauen, etwa über einen kurzen Cache-Schlüssel aus Suchbegriff und Store, der identische, kurz aufeinanderfolgende Anfragen abfängt, bevor sie erneut die Datenquellen durchlaufen. Das schützt vor Sonderfällen wie doppelt gefeuerten Events oder Nutzern, die denselben Begriff mehrfach kurz hintereinander eingeben, etwa durch Copy-Paste.
In der Praxis ist eine Kombination aus moderatem clientseitigem Debounce und einem knappen serverseitigen Limit deutlich wirksamer als der Versuch, ausschließlich über Backend-Optimierung jede einzelne Anfrage schneller zu machen, denn die schnellste Anfrage ist immer die, die gar nicht erst gestellt wird.
7. Mehrere Provider im gemeinsamen Performance-Budget
Sobald mehrere DataProvider parallel laufen, etwa Produkte, populäre Suchbegriffe und eine eigene CMS-Quelle, addieren sich deren Einzelzeiten in Autocomplete::getItems, da die Provider standardmäßig nacheinander abgefragt werden. Ein einzelner langsamer Provider verzögert damit die gesamte Antwort, selbst wenn die übrigen Provider längst fertig wären.
Für eigene Provider empfiehlt sich deshalb ein bewusstes Zeitbudget, etwa eine harte Obergrenze für die Collection-Abfrage über setPageSize sowie ein Index statt einer LIKE-Abfrage auf dem Suchfeld. Wer mehrere zusätzliche Provider ergänzt, sollte deren Gesamtlaufzeit regelmäßig gegen die ursprüngliche Antwortzeit mit nur den Standard-Providern messen, um eine schleichende Verlangsamung frühzeitig zu erkennen.
8. Messung und Monitoring der Autocomplete-Antwortzeit
Ohne Messung bleibt jede Aussage über gefühlte Geschwindigkeit spekulativ. Ein einfacher Ansatz ist ein Timing-Log direkt in Autocomplete, das die Laufzeit jedes einzelnen Providers separat protokolliert, statt nur die Gesamtzeit der Anfrage zu erfassen. So lässt sich sofort erkennen, welcher Provider bei einer Verlangsamung tatsächlich verantwortlich ist.
Für den produktiven Betrieb bietet sich an, diese Werte an ein bestehendes Monitoring wie New Relic oder ein selbst gehostetes APM-Tool weiterzugeben, mit einer Warnschwelle für die Gesamtantwortzeit der Autocomplete-Anfrage. Erfahrungsgemäß sollte diese Schwelle deutlich unter zweihundert Millisekunden liegen, da alles darüber bei schneller Eingabe als spürbares Ruckeln wahrgenommen wird.
9. Edge Cases und Abgrenzung zur Volltextsuche
Sehr kurze Suchbegriffe von ein oder zwei Zeichen sollten in den meisten Fällen gar keine Anfrage an die Provider auslösen, da die Ergebnismenge dabei ohnehin zu unspezifisch ist, um sinnvolle Vorschläge zu liefern, gleichzeitig aber unnötig Serverlast erzeugt. Eine Mindestlänge von drei Zeichen, konfigurierbar clientseitig, hat sich in der Praxis bewährt.
Wichtig bleibt die Abgrenzung zur eigentlichen Ergebnisseite nach dem Absenden der Suche: Autocomplete liefert bewusst eine reduzierte, schnelle Vorschau, während die vollständige Ergebnisseite mit Filtern, Facetten und vollständigem Relevanz-Scoring über den regulären Suchindex läuft. Diese Trennung sollte bei jeder Erweiterung des Autocomplete-Backends erhalten bleiben, um die Geschwindigkeit des Vorschlagsfelds nicht durch Funktionen zu belasten, die eigentlich auf die Ergebnisseite gehören.
| Datenquelle | Standard aktiv? | Typische Latenz | Empfohlenes Limit |
|---|---|---|---|
| Produkte (catalogsearch) | Ja | niedrig, indexbasiert | 5 bis 8 Treffer |
| Populäre Suchbegriffe | Ja | sehr niedrig | 3 bis 5 Treffer |
| CMS-Seiten (eigener Provider) | Nein | mittel ohne Index | 3 bis 4 Treffer |
| Kategorien (eigener Provider) | Nein | niedrig, indexbasiert | 3 Treffer |
| Kundenspezifische Vorschläge | Nein | hoch bei ungecachten Abfragen | nicht empfohlen ohne Caching |
Mironsoft
Magento-Entwicklung, Modul-Beratung und Systemarchitektur
Magento-Projekt, das eine zweite Meinung oder erfahrene Umsetzung braucht?
Wir entwickeln individuelle Magento-Module, beraten bei Architekturentscheidungen und übernehmen komplexe Umsetzungen, von der Service-Contract-Planung bis zum produktionsreifen Deployment.
Architektur-Beratung
Modul- und Systemarchitektur vor der Umsetzung fundiert durchdenken lassen.
Custom-Modul-Entwicklung
Individuelle Magento-Module nach Best Practices sauber umsetzen.
Code-Review & Audit
Bestehende Module auf Performance, Sicherheit und Wartbarkeit prüfen lassen.
10. Zusammenfassung
Autocomplete-Backend
Architektur
DataProviderInterface-Implementierungen liefern Items, die Autocomplete::getItems zu einer gemeinsamen Liste zusammenführt.
Erweiterung
Eigene Provider wie CMS-Seiten werden per di.xml ergänzt und folgen demselben Interface wie die Standard-Provider.
Performance
Clientseitiges Debounce spart Requests vollständig, serverseitiges Limit und Indizierung beschleunigen die verbleibenden.
Monitoring
Providerspezifisches Timing-Logging deckt langsame Datenquellen auf, bevor sie als spürbares Ruckeln auffallen.