← Back to Services

Amazon OpenSearch Service

MEDIUM

Amazon OpenSearch Service is a fully managed, auto-scaling version of OpenSearch, designed for search and analytics workloads, including low-latency vector search. It eliminates operational overhead, scales automatically based on usage, and provides optimal performance for responsive user experiences (source_page: 1, 3, 7).

Learning Objectives

  • Understand the capabilities and benefits of Amazon OpenSearch Serverless for vector search.
  • Learn to deploy and configure OpenSearch Serverless collections with associated security policies using Infrastructure as Code.
  • Grasp the process of programmatic index creation and data ingestion for vector embeddings in OpenSearch.
  • Identify and apply different storage options (Hot, UltraWarm, Cold) to optimize costs for OpenSearch workloads.

Amazon OpenSearch Service Overview

Amazon OpenSearch Service offers a managed solution for search and analytics workloads, with a serverless option for simplified operations.

Amazon OpenSearch Serverless is a fully managed, auto-scaling version of OpenSearch. It eliminates operational overhead (you don't have to manage nodes, clusters, or shards), automatically adjusts capacity based on your usage so you only pay for what you use without the risk of timeouts, and provides the best performance as it's specifically optimized for the low-latency vector search that applications need for a responsive user experience. It is a production-ready service with a robust feature set.
Amazon OpenSearch Service is designed for search and analytics workloads, providing capabilities for querying and analyzing large datasets.

OpenSearch Serverless Deployment with CloudFormation

procedure

Deploying an OpenSearch Serverless collection involves defining the collection itself along with its encryption, network, and data access policies, typically automated using CloudFormation.

CloudFormation can be used to set up the Amazon OpenSearch Serverless collection and its associated security policies for a RAG (Retrieval Augmented Generation) system.

Prerequisites

  • IaC tool (CloudFormation or Terraform) for the cluster itself.
1

Define AWSTemplateFormatVersion and Description.

Standard CloudFormation template metadata.

AWSTemplateFormatVersion: '2010-09-09'
Description: OpenSearch Serverless collection for RAG.
2

Define Parameters.

To make the collection name configurable.

Parameters:
  CollectionName:
    Type: String
    Default: pdf-conversation-vectors
    Description: The name for the OpenSearch Serverless collection.
3

Create the Encryption Policy for the collection.

This policy must be created before the collection itself to ensure data encryption.

EncryptionPolicy:
  Type: AWS::OpenSearchServerless::SecurityPolicy
  Properties:
    Type: encryption
    Name: !Sub '${CollectionName}-enc'
    Policy: !Sub |
      {
        "Rules": [
          {
            "ResourceType": "collection",
            "Resource": [
              "collection/${CollectionName}"
            ]
          }
        ],
        "AWSOwnedKey": true
      }
4

Create the Network Access Policy for the collection.

This policy defines network access rules, allowing access from the public internet for development purposes.

NetworkAccessPolicy:
  Type: AWS::OpenSearchServerless::SecurityPolicy
  Properties:
    Type: network
    Name: !Sub '${CollectionName}-net'
    Policy: !Sub |
      [
        {
          "Rules": [
            {
              "ResourceType": "collection",
              "Resource": [
                "collection/${CollectionName}"
              ]
            },
            {
              "ResourceType": "dashboard",
              "Resource": [
                "collection/${CollectionName}"
              ]
            }
          ],
          "AllowFromPublic": true
        }
      ]
5

Create the Data Access Policy for the collection.

This policy grants specific permissions (e.g., ReadDocument, WriteDocument, CreateIndex, DeleteIndex) to a specified AWS Principal (e.g., an IAM role) for interacting with indices within the collection.

DataAccessPolicy:
  Type: AWS::OpenSearchServerless::AccessPolicy
  Properties:
    Type: data
    Name: !Sub '${CollectionName}-data'
    Policy: !Sub |
      [
        {
          "Rules": [
            {
              "ResourceType": "index",
              "Resource": ["index/${CollectionName}/*"],
              "Permission": [
                "aoss:ReadDocument",
                "aoss:WriteDocument",
                "aoss:CreateIndex",
                "aoss:DeleteIndex"
              ]
            }
          ],
          "Principal": ["arn:aws:sts::198945929229:assumed-role/AWSReservedSSO_PDFConversationPermissionSet_27c1e49c62b9097d/PDFConvo"]
        }
      ]
6

Create the OpenSearch Serverless collection for vector search.

This defines the core OpenSearch Serverless collection, explicitly depending on the security policies to ensure they are created first.

VectorSearchCollection:
  Type: AWS::OpenSearchServerless::Collection
  DependsOn:
    - EncryptionPolicy
    - NetworkAccessPolicy
    - DataAccessPolicy
  Properties:
    Name: !Ref CollectionName
    Type: VECTORSEARCH
    Description: Collection for storing document vector embeddings.
7

Define Outputs.

To easily retrieve important attributes of the deployed collection, such as its name, endpoint, and ARN.

Outputs:
  CollectionName:
    Value: !Ref VectorSearchCollection
  CollectionEndpoint:
    Value: !GetAtt VectorSearchCollection.CollectionEndpoint
  CollectionArn:
    Description: The ARN of the collection.
    Value: !GetAtt VectorSearchCollection.Arn

Vector Index Setup for OpenSearch Serverless

procedure

Creating a vector index in OpenSearch is a critical step for semantic search, requiring specific mappings and KNN (k-Nearest Neighbors) settings for efficient similarity search.

A Python script utilizing the `opensearchpy` library can configure and create a vector index, such as `document-vectors`, with the necessary schema for vector embeddings and KNN parameters.

Prerequisites

  • Python environment with `boto3` and `opensearchpy` libraries installed.
  • AWS credentials configured (e.g., via AWS CLI profile) with permissions to interact with OpenSearch Serverless.
1

Configure endpoint, region, index name, and vector dimensions.

These constants define the target OpenSearch collection and the specifics of the vector index to be created.

COLLECTION_ENDPOINT = "6sxorgnw362or9e7bw0b.us-west-2.aoss.amazonaws.com"
REGION_NAME = "us-west-2"
INDEX_NAME = "document-vectors"
VECTOR_DIMENSIONS = 1536
2

Set up AWS authentication.

Authenticates the Python script to securely interact with the OpenSearch Serverless collection using AWS SigV4.

session = boto3.Session(profile_name=AWS_PROFILE, region_name=REGION_NAME)
credentials = session.get_credentials()
auth = AWSV4SignerAuth(credentials, REGION_NAME, 'aoss')
3

Create the OpenSearch client.

Initializes the client object used to send requests to the OpenSearch Serverless endpoint.

client = OpenSearch(
    hosts=[{'host': COLLECTION_ENDPOINT, 'port': 443}],
    http_auth=auth,
    use_ssl=True,
    verify_certs=True,
    connection_class=RequestsHttpConnection
)
4

Define the index body with KNN settings and mappings.

This JSON structure specifies the index settings to enable k-Nearest Neighbors (KNN) search and defines the data types and properties for fields like the vector_field, text, and document_id.

index_body = {
    'settings': {
        'index': {
            'knn': 'true',
            'knn.algo_param.ef_search': 100
        }
    },
    'mappings': {
        'properties': {
            'vector_field': {
                'type': 'knn_vector',
                'dimension': VECTOR_DIMENSIONS,
                'method': {
                    'engine': 'faiss',
                    'name': 'hnsw',
                    'parameters': {
                        'ef_construction': 100,
                        'm': 16
                    }
                }
            },
            'text': {
                'type': 'text'
            },
            'document_id': {
                'type': 'keyword'
            }
        }
    }
}
5

Check for existing index and create if not present.

Ensures idempotency; the index is only created if it doesn't already exist, preventing errors on re-runs.

if not client.indices.exists(index=INDEX_NAME):
    print(f"Creating index '{INDEX_NAME}'...")
    response = client.indices.create(index=INDEX_NAME, body=index_body)
    print(f"Index creation response: {response}")
else:
    print(f"Index '{INDEX_NAME}' already exists.")

Data Ingestion with Vectorization Lambda

procedure

A Lambda function serves as the ingestion pipeline for RAG systems, processing text, creating embeddings with Bedrock, and storing them in an OpenSearch vector index.

The Vectorization Lambda function reads processed JSON files from S3, chunks the text, calls an Amazon Bedrock embedding model (e.g., `cohere.embed-multilingual-v3`) to create vector embeddings, and then ingests these vectors along with metadata into the `document-vectors` OpenSearch index.

Prerequisites

  • OpenSearch Serverless collection and `document-vectors` index already deployed.
  • Lambda function's IAM role must have permissions for `bedrock-runtime:invoke_model`.
  • Lambda function's IAM role must have permissions to write to the OpenSearch collection (`aoss:WriteDocument`).
  • Environment variables `OPENSEARCH_ENDPOINT` and `REGION_NAME` configured in Lambda.
  • An S3 bucket (e.g., `pdf-conversation-digests`) containing processed JSON files, with a structure that allows extracting `user_id` and `document_id` from the S3 key.
1

Configure Lambda environment variables and clients.

These define the necessary endpoints, index, embedding model, and S3 bucket, and initialize AWS service clients for S3 and Bedrock.

OPENSEARCH_ENDPOINT = os.environ.get("OPENSEARCH_ENDPOINT")
REGION_NAME = os.environ.get("REGION_NAME", "us-west-2")
OPENSEARCH_INDEX_NAME = "document-vectors"
EMBEDDING_MODEL_ID = "cohere.embed-multilingual-v3"
PROCESSED_BUCKET = os.environ.get("PROCESSED_BUCKET", "pdf-conversation-digests")

s3_client = boto3.client('s3')
bedrock_client = boto3.client('bedrock-runtime', region_name=REGION_NAME)
2

Implement OpenSearch client initialization.

A helper function (`get_opensearch_client`) is used to initialize an authenticated OpenSearch client instance, using `AWSV4SignerAuth` for secure communication.

def get_opensearch_client():
    credentials = boto3.Session().get_credentials()
    auth = AWSV4SignerAuth(credentials, REGION_NAME, 'aoss')

    return OpenSearch(
        hosts=[{'host': OPENSEARCH_ENDPOINT, 'port': 443}],
        http_auth=auth,
        use_ssl=True,
        verify_certs=True,
        connection_class=RequestsHttpConnection
    )
3

Implement text chunking logic.

The `chunk_text(text)` function splits long raw text into smaller, manageable chunks based on sentence boundaries, to respect the token limits of the Bedrock embedding model (e.g., a simple character count limit of 500).

def chunk_text(text):
    sentences = deque(text.split('. '))
    chunks = []
    current_chunk = ""

    while sentences:
        sentence = sentences.popleft()
        if len(current_chunk) + len(sentence) < 500: # Simple character count limit
            current_chunk += sentence + '. '
        else:
            chunks.append(current_chunk.strip())
            current_chunk = sentence + '. '
    
    if current_chunk:
        chunks.append(current_chunk.strip())

    return chunks
4

Implement vector embedding retrieval from Bedrock.

The `get_vector_embeddings(text)` function calls the Bedrock `invoke_model` API with the specified embedding model ID (e.g., `cohere.embed-multilingual-v3`) and `search_document` input type to obtain the numerical vector representation of a text chunk.

def get_vector_embeddings(text):
    try:
        response = bedrock_client.invoke_model(
            body=json.dumps({
                "texts": [text],
                "input_type": "search_document"
            }),
            modelId=EMBEDDING_MODEL_ID,
            accept='application/json',
            contentType='application/json'
        )
        response_body = json.loads(response.get('body').read())
        return response_body['embeddings'][0]
    except ClientError as e:
        print(f"Error invoking Bedrock embedding model: {e}")
        raise e
5

Define the main Lambda handler (`lambda_handler`).

This function orchestrates the entire ingestion process: reading the processed JSON from S3, extracting document metadata, chunking the text, generating embeddings, and preparing documents for OpenSearch.

def lambda_handler(event, context):
    s3_key = event['s3_key_processed']
    bucket_name = PROCESSED_BUCKET

    try:
        file_content = s3_client.get_object(Bucket=bucket_name, Key=s3_key)['Body'].read().decode('utf-8')
        processed_data = json.loads(file_content)
        raw_text = processed_data.get('raw_text', '')

        key_parts = urllib.parse.unquote_plus(s3_key).split('/')
        user_id = key_parts[1]
        document_id = os.path.splitext(os.path.basename(s3_key))[0]

        text_chunks = chunk_text(raw_text)
        os_client = get_opensearch_client()

        # ... (ingestion logic in next step) ...
6

Process chunks and ingest into OpenSearch.

For each text chunk, a unique ID is created, a vector embedding is obtained from Bedrock, and a document with `vector_field`, `text`, `document_id`, `user_id`, and `chunk_id` is indexed into the OpenSearch collection.

        for i, chunk in enumerate(text_chunks):
            chunk_id = f"{document_id}_{i}"
            vector_embedding = get_vector_embeddings(chunk)
            os_document = {
                "vector_field": vector_embedding,
                "text": chunk,
                "document_id": document_id,
                "user_id": user_id,
                "chunk_id": chunk_id
            }

            os_client.index(
                index=OPENSEARCH_INDEX_NAME,
                body=os_document,
                id=chunk_id
            )
        
        print(f"Successfully processed {len(text_chunks)} chunks for document {document_id}")
        
        return {
            'statusCode': 200,
            'body': json.dumps({'document_id': document_id, 'user_id': user_id, 'chunks_processed': len(text_chunks)})
        }

OpenSearch Storage Tiers

Amazon OpenSearch Service offers various storage options, including hot, UltraWarm, and cold storage, to optimize performance and cost based on data access patterns and retention requirements.

Different storage tiers are available to manage OpenSearch workloads, allowing for cost savings by matching data temperature with appropriate storage.

Hot Storage

Hot storage is designed for high performance, low latency, frequently accessed, and mutable data. It incurs significant overhead due to replicas, Linux reserved space, and OpenSearch reserved space. For example, 100 GB of data with one replica can require approximately 290 GB of hot storage.
performance High performance, low latency
access_frequency Frequently accessed
data_mutability Mutable
overhead_factors Replicas, Linux reserved space, OpenSearch reserved space
generalized_storage_calculation Source data * (1 + number of replicas) * (1 + indexing overhead) / (1 - Linux reserved space) / (1 - OpenSearch Service overhead)
simplified_storage_calculation Source data * (1 + number of replicas) * 1.45
Use Cases:
  • Data requiring frequent searches, high performance, and frequent updates.

UltraWarm Storage

UltraWarm storage is for less frequently accessed, read-only data. It achieves a hot-like experience for aggregations and visualizations by combining Amazon S3 with nodes powered by the AWS Nitro System. S3 contributes durable, cost-effective storage, eliminating the requirement for replicas with its 11 nines durability, enabling each UltraWarm node to utilize its entire available storage capacity. These nodes are equipped with query processing optimizations and an advanced caching solution that proactively fetches data.
performance Hot-like experience for aggregations and visualizations
access_frequency Less frequently accessed
data_mutability Read-only
underlying_storage Amazon S3
node_system AWS Nitro System
s3_durability 11 nines
replica_requirement Eliminated
Use Cases:
  • Less frequent searches
  • Read-only data
  • Warm access to data

Cold Storage

Cold Storage is optimized for rarely accessed, read-only audit log data that is searched periodically. Unlike UltraWarm storage which have compute nodes, Cold Storage separates compute from storage, thereby lowering costs further. You can easily attach cold storage to UltraWarm nodes when you need to run search queries on your data.
performance Lowest cost for archival search
access_frequency Rarely accessed, periodic searches
data_mutability Read-only
architecture Separates compute from storage
query_access Easily attachable to UltraWarm nodes for querying
Use Cases:
  • Rarely accessed read-only audit log data
  • Periodic searches
  • Lowest cost storage tier

OpenSearch Storage Tier Comparison and Recommendations

comparison-table

Choosing the right storage tier is crucial for cost optimization in Amazon OpenSearch Service, balancing performance and access requirements.

The following outlines key characteristics and recommendations for selecting OpenSearch storage tiers based on data access patterns and performance requirements.

Option Primary Use Case Data Access Frequency Data Mutability Performance Characteristics Cost Profile
Hot Storage High performance, frequently accessed, mutable data Frequent Mutable High performance, low latency Higher cost
UltraWarm Storage Less frequently accessed, read-only data for aggregations/visualizations Less frequent Read-only Hot-like experience with advanced caching Lower cost than hot
Cold Storage Rarely accessed, read-only audit logs searched periodically Rarely accessed, periodic Read-only Requires attaching to UltraWarm nodes for querying Lowest cost

Exam Focus

  • Amazon OpenSearch Service is designed for search and analytics, not simple backup; using it for basic backup adds unnecessary cost and complexity (source_page: 3, 7).
  • When optimizing costs for Amazon OpenSearch workloads, consider UltraWarm Storage and Cold Storage as alternatives to hot storage, selecting the tier based on data access frequency and mutability requirements (source_page: 2).

Glossary

OpenSearch Serverless
A fully managed, auto-scaling version of OpenSearch that eliminates operational overhead, adjusts capacity based on usage, and is optimized for low-latency vector search.
Vector Search
A search method optimized for low-latency retrieval of relevant items based on their numerical vector representations, crucial for applications like semantic search.
Hot Storage
An OpenSearch storage tier for high performance, low latency, frequently accessed, and mutable data, incurring overhead from replicas and reserved space.
UltraWarm Storage
An OpenSearch storage tier for less frequently accessed, read-only data, combining Amazon S3 with AWS Nitro System nodes to provide a hot-like experience for aggregations and visualizations at a lower cost, eliminating the need for replicas.
Cold Storage
The lowest cost OpenSearch storage tier for rarely accessed, read-only audit log data that is searched periodically, separating compute from storage and allowing attachment to UltraWarm nodes for queries.
KNN (k-Nearest Neighbors)
A setting in OpenSearch indexes to enable k-Nearest Neighbors search, used for finding documents with vector fields closest to a query vector.

Key Takeaways

  • Amazon OpenSearch Serverless simplifies deployment and scales automatically, making it ideal for low-latency vector search applications in RAG systems (source_page: 1).
  • Effective OpenSearch solutions require deploying collections with appropriate security policies (encryption, network, data access) and configuring vector indexes with specific KNN settings for efficient data retrieval (source_page: 1).
  • OpenSearch Service offers tiered storage (Hot, UltraWarm, Cold) to optimize costs; choosing the right tier depends on the frequency of data access, its mutability, and performance needs (source_page: 2).

Content Sources

1. try with opensearch serverless AWS Cost Optimization Deep Dive 01_AWS_Solutions_Architect_Associate_... API Gateway Stage and Canary Deployments AWS Well-Architected Framework Extracted: 2026-03-25T01:05:05.967831+00:00 Model: gemini-2.5-flash