# How Semantic Search Works with Amazon Bedrock Cohere Embeddings in OpenSearch Service

> Implement semantic search with Amazon Bedrock Cohere embeddings in OpenSearch Service. This tutorial details generating vector embeddings, storing them in a k-NN index, and querying for similar products.

- 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 tutorial implements semantic search by generating vector embeddings via Amazon Bedrock's Cohere model, storing them in an OpenSearch k-NN index, and executing nearest-neighbor queries to match natural language queries with semantically similar products.**

The `aws-samples/sample-for-amazon-opensearch-service-tutorials-101` repository demonstrates a complete serverless semantic search pipeline. It combines Amazon Bedrock's Cohere embedding models with OpenSearch Service vector capabilities to enable natural language product discovery beyond traditional keyword matching.

## Generating Cohere Embeddings with Amazon Bedrock

The embedding layer centers on the `get_embedding()` function 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 utility invokes the Amazon Bedrock runtime API using the `cohere.embed-english-v3` model to convert text into high-dimensional float vectors.

### The get_embedding() Function Implementation

The function constructs a JSON payload specifying the input text, embedding type, and truncation behavior. It calls `bedrock_client.invoke_model()` with the model ID and parses the float array from the response:

```python

# artifacts/search_lambda/opensearch_search.py – get_embedding()

body = json.dumps({
    "texts": [text],
    "input_type": "search_query",
    "truncate": "END",
    "embedding_types": ["float"]
})
response = bedrock_client.invoke_model(
    modelId=MODEL_ID,               # cohere.embed-english-v3

    accept='application/json',
    contentType='application/json',
    body=body
)
response_body = json.loads(response.get('body').read())
return response_body['embeddings']['float'][0]

```

This same embedding utility is reused across both the indexing pipeline and the search API to ensure vector consistency.

## Storing Vector Embeddings in OpenSearch Service

Before search can execute, product data must be converted to vectors and indexed. The offline script [`generate_product_images_vectors.py`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/generate_product_images_vectors.py) processes raw product catalogs and enriches them with embeddings.

### Offline Embedding Generation

The script combines product titles, categories, and descriptions into a single text string, then calls `get_embedding()` to produce the vector representation:

```python

# generate_product_images_vectors.py – generate_cohere_embeddings()

vector_embedding = get_embedding(combined_text)
product['vector_embedding'] = vector_embedding

```

The resulting documents are written to an OpenSearch index configured with a **k-NN vector mapping**. The [`artifacts/index_lambda/opensearch_index.py`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/artifacts/index_lambda/opensearch_index.py) Lambda function handles the final indexing step, ensuring the `vector_embedding` field is properly mapped for approximate nearest neighbor search.

## Executing Semantic Search Queries

The search API supports two query modes: pure vector search and hybrid search. Both rely on the same Bedrock embedding generation to transform user queries into vectors.

### Vector Search Implementation

When the API receives a `type: "vector_search"` request, it embeds the search text using the Cohere model, then constructs an OpenSearch k-NN query. The query explicitly excludes the raw vector from the response to minimize payload size:

```python

# artifacts/search_lambda/opensearch_search.py – vector_search handling

vector_embedding = get_embedding(search_text)
search_body = {
    "size": 100,
    "_source": {"excludes": ["vector_embedding"]},
    "query": {"knn": {"vector_embedding": {"vector": vector_embedding, "k": 100}}}
}

```

### Hybrid Search with Keyword Filters

For scenarios requiring precise attribute matching combined with semantic similarity, the implementation supports a **hybrid_search** mode. This approach applies keyword filters (category, color, product_type) alongside the k-NN vector query, allowing users to narrow semantic results by specific product attributes.

## End-to-End Architecture Flow

The semantic search pipeline operates across seven distinct stages:

1. **Data Preparation** – [`generate_product_images_vectors.py`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/generate_product_images_vectors.py) reads raw product JSON and generates Cohere embeddings for each item.
2. **Vector Indexing** – The indexing Lambda ([`artifacts/index_lambda/opensearch_index.py`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/artifacts/index_lambda/opensearch_index.py)) persists documents with their `vector_embedding` fields to OpenSearch.
3. **Query Submission** – The front-end sends natural language queries via API Gateway to the search Lambda.
4. **Query Embedding** – `get_embedding()` converts the query text into a vector using Bedrock Cohere.
5. **k-NN Retrieval** – OpenSearch executes the nearest neighbor search against the vector index.
6. **Result Enrichment** – The Lambda generates presigned S3 URLs for product images in the result set.
7. **Response Delivery** – The enriched JSON payload returns to the UI for display.

## Key Implementation Files

- **[`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)** – Contains the core `get_embedding()` function and handles both vector and hybrid search query construction.
- **[`generate_product_images_vectors.py`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/generate_product_images_vectors.py)** – Offline script for batch-generating Cohere embeddings from product catalogs.
- **[`artifacts/index_lambda/opensearch_index.py`](https://github.com/aws-samples/sample-for-amazon-opensearch-service-tutorials-101/blob/main/artifacts/index_lambda/opensearch_index.py)** – Lambda function responsible for indexing documents with vector embeddings into OpenSearch.
- **`search_tutorials/*.py`** – CDK stacks defining the OpenSearch domain, Lambda layers, and IAM policies required for Bedrock integration.

## Summary

- The implementation uses **Amazon Bedrock's `cohere.embed-english-v3`** model to generate float vectors from product text and queries.
- **OpenSearch k-NN queries** retrieve semantically similar items by comparing query vectors against indexed product embeddings.
- The **hybrid search** mode combines vector similarity with traditional keyword filtering for refined results.
- Vector payloads are optimized by **excluding the raw embedding** from search responses to reduce latency.
- The architecture is fully serverless, utilizing Lambda functions for both indexing and search orchestration.

## Frequently Asked Questions

### What Cohere model does the tutorial use for embeddings?

The implementation specifically uses the `cohere.embed-english-v3` model ID when invoking Amazon Bedrock. This model generates high-quality English text embeddings optimized for semantic search and similarity matching tasks.

### How does the search Lambda prevent large payload sizes when returning results?

The search query explicitly sets `"_source": {"excludes": ["vector_embedding"]}` in the request body. This removes the high-dimensional float array from the response. Only the relevant product metadata and presigned image URLs transmit back to the client.

### Can the implementation combine traditional keyword search with semantic search?

Yes. The API supports a `hybrid_search` type that applies keyword filters alongside the k-NN vector query. This allows users to constrain semantic results to specific product attributes while maintaining natural language query flexibility.

### Which AWS services are integrated in this semantic search architecture?

The solution integrates **Amazon Bedrock** for Cohere embeddings and **Amazon OpenSearch Service** for vector storage and k-NN search. It also utilizes **AWS Lambda** for compute, **Amazon S3** for product images, and **Amazon API Gateway** for the search endpoint.