How to Implement Autocomplete with OpenSearch match_phrase_prefix in the AWS Sample Application

The sample application implements real-time autocomplete by combining a React Autosuggest component that sends prefix queries to an AWS Lambda function, which constructs and executes a match_phrase_prefix query against Amazon OpenSearch Service to return instant suggestions as the user types.

The aws-samples/sample-for-amazon-opensearch-service-tutorials-101 repository demonstrates a production-ready pattern for building type-ahead search functionality. This tutorial application wires together a React frontend, API Gateway, and Python Lambda to leverage OpenSearch's match_phrase_prefix query for low-latency autocomplete experiences.

Frontend Implementation with React Autosuggest

The user interface resides in keyword-prefix-page.tsx and utilizes the AWS UI Autosuggest component to capture input and display predictions.

Handling User Input Events

When a user types into the search field, the prefix_match handler triggers immediately. This function collects the current input value and the selected search attribute (such as title or description) to prepare the API request.

The handler constructs a POST payload targeting the API Gateway /search endpoint with three critical fields: attribute_name, attribute_value, and type set to "prefix_match". This explicit type parameter instructs the backend to use prefix matching logic rather than standard full-text search.

Sending Requests to the Search API

The frontend transmits the autocomplete request using the browser's Fetch API with authorization headers derived from the user's ID token. The request body specifies which field to search and the current prefix string:

async function prefix_match(search_value: string, canSuggest: boolean) {
  const token = appData.userinfo.tokens.idToken.toString();
  const response = await fetch(`${config["apiUrl"]}/search`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": token,
    },
    body: JSON.stringify({
      attribute_name: search_field,
      attribute_value: search_value,
      type: "prefix_match",
    }),
  });

  if (response.ok) {
    const resp = await response.json();
    const hits = resp.result.hits.hits;
    if (canSuggest) {
      const suggestions = hits.map(hit => ({
        value: hit._source[search_field],
      }));
      setSuggestions(suggestions);
    }
  }
}

This implementation in keyword-prefix-page.tsx (around lines 66-95) ensures that every keystroke potentially triggers a new prefix search while managing the suggestion state for the Autosuggest component.

Backend Lambda Query Construction

The opensearch_search.py Lambda function processes incoming requests and dynamically builds the appropriate OpenSearch query based on the type parameter.

Building the match_phrase_prefix Query

When the Lambda detects body["type"] == "prefix_match", it constructs a query that treats the last term of the user's input as a prefix. This allows matches where documents contain terms starting with the input string—such as "Pi" matching "Pink", "Pillow", or "Picture".

The Python implementation generates the following query structure:

elif body["type"] == "prefix_match":
    if attribute_value == "":
        search_body = {"size": 100, "query": {"match_all": {}}}
    else:
        search_body = {
            "size": 100,
            "query": {
                "match_phrase_prefix": {
                    attribute_name: {
                        "query": attribute_value,
                        "max_expansions": 10,
                        "slop": 1,
                    }
                }
            },
        }

Located around lines 52-66 in artifacts/search_lambda/opensearch_search.py, this logic handles empty inputs by falling back to match_all, ensuring the UI receives consistent response formatting even when the search field clears.

Configuring max_expansions and slop Parameters

The query utilizes two critical tuning parameters for autocomplete performance. The max_expansions value of 10 limits how many unique terms OpenSearch will generate from the prefix, preventing resource exhaustion on broad queries like single characters. The slop value of 1 permits minor word order variations, providing flexibility when users type multi-word phrases out of exact sequence.

These settings balance responsiveness with accuracy, ensuring the autocomplete remains fast even as dataset size grows.

Rendering Suggestions in the UI

After OpenSearch returns matching documents, the Lambda forwards the results back through API Gateway to the frontend. The prefix_match function extracts the relevant field values from hit._source[search_field] and maps them into the suggestions array expected by the Autosuggest component.

This mapping occurs immediately after the fetch call resolves, allowing the UI to update the dropdown list without additional processing layers. The direct field extraction ensures that suggestions display exactly the content stored in the chosen attribute—whether titles, descriptions, or other indexed text fields.

Summary

  • match_phrase_prefix enables real-time autocomplete by treating the final input term as a wildcard prefix against indexed text fields.
  • The React frontend in keyword-prefix-page.tsx sends POST requests with type: "prefix_match" to trigger specialized backend handling.
  • The Python Lambda in opensearch_search.py constructs the query with max_expansions: 10 and slop: 1 to optimize performance and flexibility.
  • This architecture delivers sub-second suggestion generation by leveraging OpenSearch's prefix matching capabilities through a serverless API stack.

Frequently Asked Questions

What is the difference between match_phrase_prefix and regular match queries in OpenSearch?

match_phrase_prefix requires terms to appear in the same order as the input, but treats the last term as a prefix that can match any terms beginning with those characters. Standard match queries analyze the input and search for individual terms independently without maintaining phrase order or prefix expansion, making them less suitable for type-ahead functionality where partial word completion is essential.

How does max_expansions affect autocomplete performance in this sample?

The max_expansions parameter limits the number of unique terms OpenSearch will match against the prefix. Setting this to 10 as implemented in opensearch_search.py prevents the query from expanding to thousands of potential matches when users type short prefixes like "a" or "th", thereby maintaining low latency and reducing computational overhead on the cluster.

Can the match_phrase_prefix query handle multiple word inputs?

Yes, match_phrase_prefix processes all terms except the last as complete words requiring exact matches, while the final term operates as a prefix. The slop parameter set to 1 in this implementation allows minor deviations in word ordering, meaning a query for "red pill" could match documents containing "pill red" or "red pillow" depending on the indexed content and analyzer configuration.

Why does the sample use a specific "prefix_match" type parameter instead of auto-detecting the query format?

Using an explicit type: "prefix_match" parameter in the API payload creates clear separation between different search modes (such as exact match, fuzzy search, or autocomplete) within the Lambda handler. This approach simplifies debugging, allows distinct authorization rules per query type, and prevents accidental prefix matching on fields where full-text relevance scoring would be more appropriate.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →