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

> Learn how the AWS sample app uses match_phrase_prefix for instant autocomplete. Explore React Autosuggest and OpenSearch for real-time suggestions as users type.

- Repository: [AWS Samples/sample-for-amazon-opensearch-service-tutorials-101](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101)
- Tags: how-to-guide
- Published: 2026-02-25

---

**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`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/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:

```typescript
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`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/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`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/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:

```python
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`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/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`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/keyword-prefix-page.tsx) sends POST requests with `type: "prefix_match"` to trigger specialized backend handling.
- The Python Lambda in [`opensearch_search.py`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/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`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/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.