Erstellen von umfangsgebundenen Suchvorschlägen und Korrekturen für Suchabfragen

blog-search-results-dark-720x420.png

Sie haben nur eine Gelegenheit, um mit relevanten Suchergebnissen dafür zu sorgen, dass die Kunden auf Ihrer E-Commerce-Website bleiben. Laut einer Umfrage von Harris verlassen 76 % aller Online-Einkäufer eine Einzelhandels-Website nach einer erfolglosen Suche.

Daher ist es entscheidend, Ihr Sucherlebnis so zu optimieren, dass die Kunden gesuchte Produkte schnell finden. Die Theorie hinter modernen Sucherlebnissen funktioniert so: Heutzutage reicht es nicht aus, einfach nur eine Suchleiste anzubieten, die passende Produkte zurückgibt. E-Commerce-Websites müssen eine ganze Reihe an Such-Tools anbieten, um die Nutzer persönlich zu den gewünschten Produkten zu führen.

In diesem Blogeintrag erfahren Sie, wie Sie Ihre E‑Commerce-Suche mit zwei häufig verwendeten Features optimieren können: umfangsgebundene Vorschläge und Abfragekorrekturen („Meinten Sie [...]?“).

Die folgenden Beispiele wurden mit Elastic 8.5 getestet. 

Umfangsgebundene Vorschläge 

E-Commerce-Einzelhändler stehen oft vor der Herausforderung, umfangreiche Produktkataloge mit vielen verschiedenen Kategorien im Angebot zu haben. In diesem Szenario ist es schwierig, mit einer einfachen Abfrage genau zu ermitteln, für welche Domäne oder Kategorie sich ein Nutzer möglicherweise interessiert. Wenn ein Nutzer bei einem Einzelhändler für Elektronikprodukte nach „Flachbildschirm“ sucht, werden beispielsweise Ergebnisse aus den Kategorien Fernseher, Fernsehhalterungen, Computerbildschirme usw. angezeigt. Eine Auflistung von Halterungen für Fernseher ist möglicherweise wenig relevant in dieser Phase, wenn ein Nutzer nach einem Fernseher sucht.

Umfangsgebundene Vorschläge helfen den Nutzern, ihre Suche auf relevante Themen einzugrenzen, indem sie Abfragen innerhalb bestimmter Kategorien oder Marken vorschlagen.

Mit diesem leistungsstarken Feature gelangen die Nutzer sehr schnell zu einem verfeinerten Ergebnissatz. Außerdem können Sie umfangsgebundene Suchvorschläge mit Search UI und Elastic mühelos implementieren. Im nächsten Abschnitt erfahren Sie genau, wie Sie dazu vorgehen können. 

Daten für Vorschläge sammeln

Wie im obigen Beispiel beschrieben erhalten die Benutzer Vorschläge für Abfragen und relevante Bereiche, noch während sie ihre Anfrage eingeben. Diese Vorschläge werden oft anhand von Analytics-Daten erstellt, bei denen die gängigsten Nutzeranfragen zu den jeweils gesuchten Bereichen zugeordnet werden.

Angenommen, die Analytics-Daten für unsere E-Commerce-Website haben ergeben, dass die Top-Abfrage „lcd tv“ lautet und dass die Nutzer dazu am häufigsten auf die Kategorie „TV und Heimkino“ klicken.

Mit diesen Daten können wir ein Dokument erstellen, das einen entsprechenden umfangsgebundenen Vorschlag darstellt: 

{
   "name": "lcd tv",
   "weight": 112,
   "category": {
       "name": "TV & Home Theater",
       "value": 111
   }
}

Dieses Dokument enthält eine Abfrage und eine zugeordnete Kategorie. Bei Bedarf können wir komplexere  Zusammenhänge erstellen, etwa um eine Liste von Kategorien oder einen weiteren Umfang wie etwa „Marken“ zu verwenden.

Anschließend erstellen wir einen dedizierten Index in Elasticsearch, nennen ihn „suggest“ und füllen ihn mit einer Liste von umfangsgebundenen Vorschlägen, die wir anhand unserer Analytics-Daten erstellt haben. Dazu können wir Datentransformationen oder selbstgeschriebenen Code verwenden, etwa in Form eines Python-Skripts. Das Index-Mapping für unseren Beispiel-Index „suggest“  finden Sie hier

Automatische Vervollständigung mit Vorschlägen

Nachdem unsere Liste mit Vorschlägen einsatzbereit ist, können wir sie zu unserem Sucherlebnis hinzufügen.

In Search UI können wir innerhalb weniger Minuten ein Sucherlebnis mit Elastic erstellen. Anschließend können wir die neu erstellte Benutzeroberfläche als Basis für unsere umfangsgebundenen Vorschläge verwenden.

Search UI verwendet ein Konfigurationsobjekt, um die Suche an Ihre Anforderungen anzupassen. Unten sehen Sie einen Ausschnitt des Konfigurationsobjekts für die Vorschläge. In diesem Fall geben wir an, welcher Index und welche Felder abgefragt werden und welche Felder im Ergebnis zurückgegeben werden sollen:

suggestions: {
     types: {
       popularQueries: {
         search_fields: {
           "name.suggest": {} // fields used to query
         },
         result_fields: {
           name: {
             raw: {}
           },
           "category.name": {
             raw: {}
           }
         },
         index: "suggest",
         queryType: "results"
       }
     },
     size: 5
   }

Anschließend konfigurieren wir die SearchBox-Komponente so, dass die Kategorie als teil der Abfrage übergeben wird, wenn wir zur Seite mit den Suchergebnissen navigieren:

// Search bar component
<SearchBox
   onSelectAutocomplete={(suggestion, config, defaultHandler) => {
       // User selects a scoped suggestion - Category
       if (suggestion.name && suggestion.category) {
           const params = { q: suggestion.name.raw, category: suggestion.category.raw.name };
           // Navigate to search result page with category passed as parameters
           navigate({
               pathname: '/search',
               search: `?${createSearchParams(params)}`,
           });
       // User selects normal suggestion
       } else if (suggestion) {
           // Navigate to search result page
           window.location.href = "/search?q=" + suggestion.suggestion;
       }
       defaultHandler(suggestion);
   }}
   autocompleteSuggestions={{
       popularQueries: {
           sectionTitle: "Popular queries",
           queryType: "results",
           displayField: "name",
           categoryField: "category"
       }
   }}
   autocompleteView={AutocompleteView}
/>

Beachten Sie, dass wir eine AutocompleteView-Funktion übergeben, um die Autocomplete-Ansicht anzupassen und die Kategorie neben der vorgeschlagenen Abfrage anzeigen zu können. 

Unten sehen Sie einen Ausschnitt der AutocompleteView-Funktion, mit der wir eine Abfrage zusammen mit dem zugeordneten Umfang anzeigen: 

{suggestions.slice(0,1).map((suggestion) => {
   index++;
   const suggestionValue = getDisplayField(suggestion)
   const suggestionScope = getCategoryField(suggestion)
   return (
     <li
       {...getItemProps({
         key: suggestionValue,
         index: index - 1,
         item: {
           suggestion: suggestionValue,
           ...suggestion.result
         }
       })}
     >
       <span>{suggestionValue}</span>
       <ul><span style={{marginLeft: "20px"}}>in {suggestionScope}</span></ul>
     </li>
   );
})}

Auf der Seite mit den Suchergebnissen müssen wir dann nur noch die Abfrageparameter verarbeiten und den Ergebnissatz filtern: 

 const [searchParams] = useSearchParams();
   useEffect(() => {
       if (searchParams.get('category')) addFilter("department", [searchParams.get('category')], "all")
   }, [searchParams]);

Nach Abschluss dieser Schritte sieht das Ergebnis so aus:

Video thumbnail

Abfragekorrekturen („Meinten Sie [...]?“)

Kunden reagieren schnell frustriert, wenn ihnen aufgrund von ungenauen Suchabfragen oder Schreibfehlern relevante Suchergebnisse entgehen. Um zu vermeiden, keine oder nur wenige Suchergebnisse zurückzugeben, ist es oft hilfreich, eine bessere Abfrage zu empfehlen, auch bekannt als „Meinten Sie [...]?“.

Dieses Feature kann auf viele verschiedene Arten implementiert werden, aber wir stellen Ihnen hier den einfachsten Weg mit Search UI und Elastic vor. 

Daten analysieren

Der Datensatz, den wir für unserMeinten Sie [...]?“-Feature verwenden, ähnelt den Daten für die umfangsgebundenen Vorschläge, da wir den Nutzern beliebte Abfragen empfehlen möchten, falls ihre Abfrage keine Ergebnisse geliefert hat.  

Wir verwenden eine ähnliche Dokumentstruktur für „Meinten Sie [...]?“.

{
   "name": "lcd tv",
   "weight": 112,
   "category": {
       "name": "TV & Home Theater",
       "value": 111
   }
}

Der Schlüssel dazu ist die Art und Weise, wie Daten in Elasticsearch indexiert werden. Um relevante Vorschläge anbieten zu können, benötigen Sie bestimmte Elasticsearch-Features wie etwa benutzerdefinierte Analyzer.

Unten sehen Sie die im Beispiel verwendeten Index-Einstellungen und -Mappings: 

{
    "settings":
    {
        "index":
        {
            "number_of_shards": 1,
            "analysis":
            {
                "analyzer":
                {
                    "trigram":
                    {
                        "type": "custom",
                        "tokenizer": "standard",
                        "filter":
                        [
                            "lowercase",
                            "shingle"
                        ]
                    },
                    "reverse":
                    {
                        "type": "custom",
                        "tokenizer": "standard",
                        "filter":
                        [
                            "lowercase",
                            "reverse"
                        ]
                    }
                },
                "filter":
                {
                    "shingle":
                    {
                        "type": "shingle",
                        "min_shingle_size": 2,
                        "max_shingle_size": 3
                    }
                }
            }
        }
    },
    "mappings":
    {
        "properties":
        {
            "category":
            {
                "properties":
                {
                    "name":
                    {
                        "type": "text",
                        "fields":
                        {
                            "keyword":
                            {
                                "type": "keyword",
                                "ignore_above": 256
                            }
                        }
                    },
                    "value":
                    {
                        "type": "long"
                    }
                }
            },
            "name":
            {
                "type": "search_as_you_type",
                "doc_values": "false",
                "max_shingle_size": 3,
                "fields":
                {
                    "reverse":
                    {
                        "type": "text",
                        "analyzer": "reverse"
                    },
                    "suggest":
                    {
                        "type": "text",
                        "analyzer": "trigram"
                    }
                }
            },
            "weight":
            {
                "type": "rank_feature",
                "fields":
                {
                    "numeric":
                    {
                        "type": "integer"
                    }
                }
            }
        }
    }
}

In der Suggester-Dokumentation finden Sie ausführliche Informationen dazu, warum wir bestimmte Einstellungen und Mappings verwenden, um relevante Vorschläge abzurufen. 

Suche vorbereiten

Nachdem Ihr Index einsatzbereit ist, können Sie sich mit dem Sucherlebnis befassen. Nutzen Sie die Elasticsearch-API, um Vorschläge auf Basis einer Abfrage abzurufen. Falls Sie den Client möglichst einfach halten möchten, können Sie eine Suchvorlage in Elasticsearch erstellen, die die Abfrage enthält. Anschließend können Sie diese Suchabfrage auf der Client-Seite einfach ausführen:

PUT _scripts/did-you-mean-template
{
   "script": {
       "lang": "mustache",
       "source": {
           "suggest": {
               "text": "{{query_string}}",
               "simple_phrase": {
                   "phrase": {
                       "field": "name.suggest",
                       "size": 1,
                       "direct_generator": [
                           {
                               "field": "name.suggest",
                               "suggest_mode": "always"
                           },
                           {
                               "field": "name.reverse",
                               "suggest_mode": "always",
                               "pre_filter": "reverse",
                               "post_filter": "reverse"
                           }
                       ]
                   }
               }
           }
       }
   }
}

Vorschläge von der Anwendung erhalten

Um Vorschläge von Elasticsearch zu erhalten, fügen wir eine Backend-API hinzu, die für den Client unter /api/suggest verfügbar ist. Diese neue API ruft Elasticsearch auf, führt die Suchabfrage aus, übergibt die Abfrage, für die Sie Vorschläge erhalten möchten, und gibt dann einen Abfragevorschlag zurück. Mit der Backend-API können wir die Komplexität im Frontend reduzieren.

client.searchTemplate({
       index: "suggest",
       id: 'did-you-mean-template',
       params: {
           query_string: req.body.query
       }
   })

Für die Abfrage „Lutsprecher“ gibt die API beispielsweise den Vorschlag „Lautsprecher“ zurück. Dazu verwenden wir die zuvor ingestierten Daten mit den am häufigsten verwendeten Abfragen. Die suggest-API gibt einen Begriff zurück, der der Suchabfrage syntaktisch möglichst ähnlich ist. 

„Meinten Sie [...]?“ zur Ergebnisseite hinzufügen

Jetzt können wir das „Meinten Sie [...]?“-Feature zur Frontend-Anwendung hinzufügen. Dazu verwenden wir weiterhin dieselbe React-Anwendung wie für die umfangsgebundenen Vorschläge. 

Die React-Anwendung kann die neu hinzugefügte API abfragen und einen Vorschlag anzeigen, falls die aktuelle Abfrage keine Ergebnisse liefert. 

Das Ziel besteht darin, einen Vorschlag für jede von den Nutzern eingegebene Abfrage zu erhalten. Wenn kein Ergebnis vorhanden ist, wird stattdessen der Vorschlag angezeigt. Alternative Implementierungen sind ebenfalls möglich: Sie können Vorschläge anzeigen, falls nur wenige Ergebnisse vorhanden sind, oder Sie können den Vorschlag automatisch anstelle der Abfrage des Nutzers ausführen.

Unsere Anwendung verwendet eine React-Komponente mit dem Namen SearchResults, um die Suchergebnisse anzuzeigen. An dieser Stelle können wir eine Funktion hinzufügen, um den Vorschlag von unserer Backend-API /api/suggest abzurufen.

const fetchDidYouMeanSuggestion = async (query) => {
   const response = await fetch('/api/did_you_mean', {
       method: 'POST',
       headers: {
           Accept: 'application/json, text/plain, */*',
           'Content-Type': 'application/json',
       },
       body: JSON.stringify(query)
   })
   const body = await response.json();
   if (response.status !== 200) throw Error(body.message);
   return body;
}

Wenn die Nutzer ihre Abfrage verfeinern und ändern, können Sie den Vorschlag aktualisieren, indem Sie die API aufrufen:

   // Get search params from dom router
   const [searchParams] = useSearchParams();
 
   useEffect(() => {
       // When the searchParams contains a query
       if (searchParams.get('q')) {
           // Set query for Search UI - Run the search
           setSearchTerm(searchParams.get('q'))
           // Fetch suggestion from backend API
           fetchDidYouMeanSuggestion({ query: searchParams.get('q') }).then(res => {
               setSuggestion(res.body?.suggest?.simple_phrase[0]?.options[0]?.text)
           })
               .catch(err => console.log(err));
       }
  }, [searchParams]);

Zuletzt zeigen wir den Vorschlag an, falls die Nutzerabfrage keine Ergebnisse geliefert hat:

{wasSearched && totalResults == 0 && <span>No results to show{suggestion ? <>, did you mean <span style={{ cursor: "pointer", color: "blue" }} onClick={() => navigateSuggest(suggestion)}>{suggestion}</span>?</> : "."}</span>}

Das Ergebnis sieht wie folgt aus:

Video thumbnail

Fazit

In diesem Blogeintrag haben Sie erfahren, wie Sie die Features „Meinten Sie [...]?“ und umfangsgebundene Vorschläge mit Elastic Enterprise Search mühelos umsetzen können. Anschließend können Sie die Features problemlos in Ihr vorhandenes Sucherlebnis integrieren, damit Ihre Nutzer die gesuchten Ergebnisse schneller finden. Den in diesen Beispielen verwendeten Code finden Sie in diesem GitHub-Repository.

Ein modernes Sucherlebnis ist entscheidend für E-Commerce-Websites und viele weitere Anwendungsfälle, wie etwa Kundensupport, Website-Suche, Intranet-Suche am Arbeitsplatz sowie für benutzerdefinierte Suchanwendungen. Mit den in diesem Blogeintrag beschriebenen Schritten können Sie im Handumdrehen ein besseres Sucherlebnis für Ihre Endnutzer erstellen.