How Semantic Search Works with Amazon Bedrock Cohere Embeddings in OpenSearch Service
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. 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:
# 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 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:
# 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 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:
# 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:
- Data Preparation –
generate_product_images_vectors.pyreads raw product JSON and generates Cohere embeddings for each item. - Vector Indexing – The indexing Lambda (
artifacts/index_lambda/opensearch_index.py) persists documents with theirvector_embeddingfields to OpenSearch. - Query Submission – The front-end sends natural language queries via API Gateway to the search Lambda.
- Query Embedding –
get_embedding()converts the query text into a vector using Bedrock Cohere. - k-NN Retrieval – OpenSearch executes the nearest neighbor search against the vector index.
- Result Enrichment – The Lambda generates presigned S3 URLs for product images in the result set.
- Response Delivery – The enriched JSON payload returns to the UI for display.
Key Implementation Files
artifacts/search_lambda/opensearch_search.py– Contains the coreget_embedding()function and handles both vector and hybrid search query construction.generate_product_images_vectors.py– Offline script for batch-generating Cohere embeddings from product catalogs.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-v3model 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →