Autocomplete-Vorschläge der Magento-Suche im Backend anpassen
AI generated
M2
di.xml
Magento 2
Autocomplete-Vorschläge der Suche im Backend anpassen
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.

10 Min. Lesezeit Autocomplete DataProvider Performance GraphQL

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.

11. FAQ: Autocomplete-Backend

1Sind Kategorien standardmäßig Teil der Magento-Autocomplete-Vorschläge?
Nein, im Standard sind nur Produkte und populäre Suchbegriffe aktiv, Kategorien und CMS-Seiten müssen über einen eigenen DataProvider ergänzt werden.
2Welche Methode muss ein eigener Autocomplete-Provider implementieren?
DataProviderInterface mit der Methode getItems, die eine Liste von ItemInterface-Objekten mit Titel und Ziel-URL zurückliefert.
3Wo lege ich die Reihenfolge der Datenquellen in den Vorschlägen fest?
Über die Reihenfolge der Einträge im dataProviders-Array in der di.xml, die Konfigurationsreihenfolge bestimmt direkt die Anzeigereihenfolge.
4Was steuert den Konfigurationspfad catalog/search/autocomplete_limit?
Die maximale Anzahl an Vorschlägen pro Anfrage, ein niedrigerer Wert reduziert direkt die Antwortzeit, weil weniger Treffer verarbeitet werden.
5Ist clientseitiges oder serverseitiges Debounce wirkungsvoller?
Clientseitiges Debounce ist der wirksamere Hebel, weil vermiedene Anfragen komplett wegfallen, statt nur schneller verarbeitet zu werden.
6Wie schnell sollte eine Autocomplete-Antwort im Idealfall sein?
Deutlich unter zweihundert Millisekunden, alles darüber wird bei schneller Eingabe als spürbares Ruckeln wahrgenommen.
7Warum sollte ein CMS-Page-Provider nicht über eine ungefilterte LIKE-Abfrage laufen?
Weil eine ungefilterte LIKE-Abfrage bei wachsender Seitenzahl spürbar langsamer wird als eine indexbasierte Suche, ein einfacher Titel-Index hilft ab einigen hundert Seiten.
8Läuft Autocomplete über denselben Anfragepfad wie die vollständige Suchergebnisseite?
Nein, Autocomplete nutzt einen schlankeren, auf Geschwindigkeit optimierten Pfad ohne die volle Facetten- und Relevanzberechnung der Ergebnisseite.
9Ab welcher Zeichenlänge sollte eine Autocomplete-Anfrage überhaupt ausgelöst werden?
Erfahrungsgemäß ab drei Zeichen, kürzere Eingaben liefern zu unspezifische Ergebnisse und erzeugen unnötige Serverlast.
10Wie erkenne ich, welcher Provider für eine langsame Autocomplete-Antwort verantwortlich ist?
Über providerspezifisches Timing-Logging in Autocomplete::getItems, das die Laufzeit jedes Providers einzeln statt nur die Gesamtzeit erfasst.