Application search does not always require a managed Elasticsearch service. For teams that want more control over infrastructure, deployment, configuration, and operating costs, OpenSearch can be deployed and managed directly.

OpenSearch provides search and indexing capabilities that can support product search, document search, log analysis, internal portals, and other applications that need more than a traditional database query.

The important part is understanding what you take responsibility for when you operate OpenSearch yourself.

A self-managed search system gives you control, but you also become responsible for capacity planning, backups, upgrades, security, monitoring, and failure recovery.

This article explains how to build an application search setup with OpenSearch without depending on a managed Elasticsearch service.

What Self-Managed OpenSearch Means

With a managed search service, the provider usually handles much of the underlying infrastructure.

With self-managed OpenSearch, your team operates the search cluster.

A simplified architecture looks like this:

Code
Application
     |
     v
Search API
     |
     v
OpenSearch Cluster
     |
     +-- Indexes
     +-- Shards
     +-- Replicas
     +-- Storage

The application should normally communicate with OpenSearch through a controlled service boundary rather than allowing every part of the application to access the cluster directly.

For example:

Code
Web Application
      |
      v
Search Service
      |
      v
OpenSearch

This keeps search-specific logic in one place.

When OpenSearch Makes Sense

OpenSearch can be a good choice when an application needs:

  • Full-text search

  • Filtering

  • Sorting

  • Search suggestions

  • Faceted navigation

  • Aggregations

  • Large searchable document collections

  • Flexible indexing

  • Search ranking

It can also be useful when the team already has infrastructure for running stateful services.

However, self-managing OpenSearch is not automatically simpler than using a managed service.

The operational requirements should be considered before choosing the architecture.

Basic OpenSearch Architecture

A production deployment normally contains more than one OpenSearch node.

A simplified cluster might look like:

Code
                Application
                     |
                     v
              Search Service
                     |
                     v
              Load Balancer
                     |
          +----------+----------+
          |          |          |
          v          v          v
      OpenSearch OpenSearch OpenSearch
        Node 1      Node 2      Node 3
          |          |          |
          +----------+----------+
                     |
                     v
              Persistent Storage

Multiple nodes provide better availability and allow data and search workload to be distributed across the cluster.

The exact topology depends on workload size and availability requirements.

Start With a Development Environment

Before deploying a cluster, start with a small local environment.

A containerized setup is convenient for development because it allows the application team to run OpenSearch without installing the entire stack directly on the operating system.

For example:

Code
services:
  opensearch:
    image: opensearchproject/opensearch:latest
    environment:
      - discovery.type=single-node
      - DISABLE_SECURITY_PLUGIN=true
      - OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m
    ports:
      - "9200:9200"

The exact image version should be pinned for repeatable development environments.

Avoid using an unpinned latest tag in production.

Connect a Rails Application

A Rails application can communicate with OpenSearch through an HTTP client or a compatible Ruby library.

A simple service object can keep search logic separate from controllers.

Python
class ProductSearch
  def initialize(client)
    @client = client
  end

  def search(query)
    @client.search(
      index: "products",
      body: {
        query: {
          multi_match: {
            query: query,
            fields: ["name", "description"]
          }
        }
      }
    )
  end
end

The exact client depends on the application's OpenSearch integration.

The important design principle is to avoid scattering raw search requests throughout controllers and models.

Connect a .NET Application

A .NET application can also isolate OpenSearch access behind a dedicated service.

For example:

C#
public class ProductSearchService
{
    private readonly HttpClient _client;

    public ProductSearchService(HttpClient client)
    {
        _client = client;
    }

    public async Task<string> SearchAsync(string query)
    {
        var request = new
        {
            query = new
            {
                multi_match = new
                {
                    query,
                    fields = new[]
                    {
                        "name",
                        "description"
                    }
                }
            }
        };

        var response = await _client.PostAsJsonAsync(
            "products/_search",
            request);

        response.EnsureSuccessStatusCode();

        return await response.Content.ReadAsStringAsync();
    }
}

In a production application, map the response into application-specific models instead of returning raw JSON throughout the application.

Create an Index Mapping

Search quality depends heavily on how documents are indexed.

For example:

JSON
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "category": {
        "type": "keyword"
      },
      "price": {
        "type": "double"
      },
      "createdAt": {
        "type": "date"
      }
    }
  }
}

The distinction between text and keyword fields is important.

A text field is generally used for full-text search.

A keyword field is generally useful for exact matching, filtering, grouping, and sorting.

Choosing the wrong field type can make application queries harder or less efficient later.

Keep Database Data and Search Data Separate

OpenSearch should usually be treated as a search-oriented representation of application data.

For example:

Code
PostgreSQL
    |
    | Source of truth
    v
Application
    |
    | Indexing pipeline
    v
OpenSearch
    |
    v
Search Results

Do not automatically treat OpenSearch as the authoritative transactional database.

Your application database may contain relationships, transactions, constraints, and business rules that do not belong in the search index.

The search index should contain the data required to answer search requests efficiently.

Index Documents From the Application

Suppose the application stores products in a relational database.

A search document might contain:

JSON
{
  "id": 101,
  "name": "Wireless Keyboard",
  "description": "Compact keyboard for office use",
  "category": "accessories",
  "price": 79.99
}

The application can index this document after the product is created or updated.

A common architecture is:

Code
Database Transaction
        |
        v
Application Event
        |
        v
Background Job
        |
        v
OpenSearch Index

Using a background job prevents search indexing from unnecessarily slowing down the user's request.

Handle Search Indexing Failures

The database and search index can temporarily become inconsistent.

For example:

Code
Database update
      |
      v
Successful

OpenSearch update
      |
      v
Failed

The application should have a recovery strategy.

Possible approaches include:

  • Retry queues

  • Dead-letter queues

  • Periodic reconciliation

  • Reindexing jobs

  • Event-based indexing

  • Change tracking

Do not assume that one successful indexing request means the systems will remain synchronized forever.

Design for Idempotent Indexing

An indexing operation should ideally be safe to repeat.

For example, use a stable document identifier:

Code
Product ID 101
      |
      v
OpenSearch document ID 101

If the indexing job runs twice, the second operation should update the same document rather than create an unintended duplicate.

This becomes particularly important when background jobs are retried.

Use Bulk Indexing for Large Data Sets

Indexing records individually can create unnecessary network overhead.

For initial data loads or large synchronization jobs, use bulk operations.

Conceptually:

Code
Product 1 ─┐
Product 2 ─┤
Product 3 ─┼──> Bulk Request ──> OpenSearch
Product 4 ─┤
Product 5 ─┘

Bulk indexing can significantly reduce request overhead.

However, inspect individual item failures in the bulk response.

A successful HTTP response does not necessarily mean every document was indexed successfully.

Build Search Queries Around User Intent

A search box usually needs more than a simple exact match.

For example:

CSS
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "wireless keyboard",
            "fields": [
              "name^3",
              "description"
            ]
          }
        }
      ],
      "filter": [
        {
          "term": {
            "category": "accessories"
          }
        }
      ]
    }
  }
}

This separates relevance-oriented searching from exact filtering.

The field weighting can help important fields contribute more strongly to ranking.

Do not increase boosts blindly. Validate the resulting search quality with real queries.

Add Pagination

Search results should not return thousands of documents in a single response.

A simple request might use:

CSS
{
  "from": 0,
  "size": 20,
  "query": {
    "match": {
      "name": "keyboard"
    }
  }
}

For large result sets, consider search pagination approaches appropriate for your OpenSearch version and workload.

The application should also impose a maximum page size.

For example:

Code
Requested size: 5000
Allowed maximum: 100
Actual size: 100

Never allow clients to control resource-heavy search parameters without limits.

Add Filters and Facets

Application search often requires filters such as:

  • Category

  • Brand

  • Price range

  • Availability

  • Location

  • Date

  • Status

For example:

CSS
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "name": "laptop"
        }
      },
      "filter": [
        {
          "term": {
            "brand": "ExampleBrand"
          }
        }
      ]
    }
  }
}

Filters should be based on appropriately mapped fields.

Do not use full-text fields for exact filters when a keyword-style field is more appropriate.

Protect the OpenSearch Cluster

A self-managed cluster should not be exposed directly to the public internet unless there is a very specific and carefully designed reason.

A safer architecture is:

Code
Internet
   |
   v
Application API
   |
   v
Private Network
   |
   v
OpenSearch

Apply:

  • Authentication

  • Authorization

  • TLS

  • Network restrictions

  • Least-privilege credentials

  • Secret management

  • Firewall rules

Application users should generally not receive direct OpenSearch credentials.

Separate Application and Administrative Access

The application does not need administrative permissions.

Create separate access levels for:

Code
Application
    -> Search and document operations required by the application

Operations
    -> Cluster and index administration

Monitoring
    -> Read-only metrics and health information

This limits the impact of compromised application credentials.

Monitor the Cluster

Self-managed OpenSearch requires operational monitoring.

At minimum, monitor:

  • CPU

  • Memory

  • JVM usage

  • Disk usage

  • Search latency

  • Indexing latency

  • Request rate

  • Error rate

  • Cluster health

  • Shard status

  • Unassigned shards

  • Storage growth

A search cluster can remain technically available while gradually becoming unhealthy because of storage pressure or resource exhaustion.

Monitoring should detect these conditions before users experience failures.

Plan Capacity Before Production

Do not size a production cluster only by the current document count.

Consider:

Code
Documents
+
Document size
+
Index overhead
+
Replicas
+
Query traffic
+
Indexing traffic
+
Growth
=
Required capacity

Also account for operational overhead.

A cluster that has enough disk space today may not have enough capacity after several months of growth.

Configure Replicas Carefully

Replicas can improve availability and distribute search workload.

For example:

Code
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  }
}

The appropriate values depend on cluster size and workload.

Do not create a large number of shards simply because the cluster has multiple nodes.

Too many small shards can create unnecessary overhead.

Plan Backups and Recovery

Search indexes should not be treated as disposable unless the application has a reliable way to rebuild them.

Define:

  • Backup frequency

  • Retention period

  • Recovery procedure

  • Recovery testing

  • Index rebuild process

  • Required recovery time

A backup strategy is incomplete until restoration has been tested.

For applications where the relational database is the source of truth, a full reindexing process can also provide an important recovery path.

Handle Search Downtime Gracefully

Search should not always be allowed to take down the entire application.

For example:

Code
OpenSearch available
      |
      v
Normal search

OpenSearch unavailable
      |
      v
Fallback behavior
      |
      v
Application remains usable

Depending on the application, fallback behavior might include:

  • Showing recent results

  • Using database search for limited cases

  • Returning a controlled error

  • Disabling advanced filters temporarily

The right fallback depends on the business requirements.

Common Mistakes

Treating OpenSearch Like a Database

OpenSearch is optimized for search and analytics workloads, not as a replacement for every transactional database feature.

Exposing OpenSearch Directly to Users

Keep cluster access behind controlled application services.

Using the Same Credentials Everywhere

Separate application, administrative, and monitoring access.

Ignoring Indexing Failures

Build retry and reconciliation mechanisms.

Returning Large Search Results

Use pagination and enforce maximum page sizes.

Creating Too Many Shards

Shard counts should be based on actual data and workload requirements.

Skipping Recovery Testing

A backup that has never been restored should not be considered a proven recovery strategy.

Troubleshooting Common Problems

Search Returns No Results

Check:

  • Index name

  • Field mapping

  • Analyzer configuration

  • Query field

  • Filter values

  • Document indexing status

Search Results Are Poor

Review:

  • Analyzer configuration

  • Field boosts

  • Query structure

  • Synonyms

  • Stop words

  • Search test cases

Do not immediately change the ranking formula. First determine whether the documents are being analyzed and indexed as expected.

Indexing Is Slow

Check:

  • Bulk batch size

  • Network latency

  • Refresh behavior

  • CPU

  • Memory

  • Disk performance

  • Document size

Cluster Becomes Unhealthy

Inspect:

  • Disk utilization

  • Shard allocation

  • Node availability

  • JVM memory

  • Recent indexing spikes

  • Failed operations

Do not simply add nodes without identifying the underlying bottleneck.

Best Practices

Keep OpenSearch Behind an Application Boundary

Centralize search logic in a service or repository layer.

Treat the Database as the Source of Truth

Use OpenSearch as the searchable representation unless the architecture intentionally requires otherwise.

Make Indexing Idempotent

Stable document identifiers make retries safer.

Use Background Processing

Do not make every user request wait for search indexing.

Test Search Relevance

Functional correctness is not enough. Validate the quality of returned results.

Monitor Before Problems Become Incidents

Track cluster health, resource utilization, search latency, and indexing failures continuously.

Plan for Reindexing

Mappings and analyzers can change. A reliable reindexing process makes future improvements easier.

Advantages of Self-Managed OpenSearch

A self-managed OpenSearch deployment provides:

  • Control over infrastructure

  • Control over configuration

  • Flexible deployment options

  • Custom capacity planning

  • Potentially predictable infrastructure costs

  • Ability to integrate with existing operational systems

  • Greater control over data placement

It can be especially useful for teams that already operate containerized or stateful infrastructure.

Disadvantages and Considerations

The main cost is operational responsibility.

Your team may need to manage:

  • Cluster upgrades

  • Security

  • Backups

  • Monitoring

  • Capacity planning

  • Storage

  • Shard allocation

  • Node failures

  • Recovery

  • Search performance

  • Index lifecycle management

A managed service can reduce some of this operational burden.

Therefore, the right comparison is not simply infrastructure cost versus software cost. Include engineering and operational effort in the decision.

When Self-Managed OpenSearch Is a Good Fit

Self-managed OpenSearch can make sense when:

  • The team has infrastructure expertise

  • Search is a core application capability

  • The workload requires custom configuration

  • Data placement requirements favor direct control

  • Existing infrastructure can host stateful services

  • The team is prepared to operate the cluster

A managed solution may be preferable when the organization wants to minimize operational responsibility.

Summary

OpenSearch can provide a strong search platform without relying on a managed Elasticsearch service, but self-management changes the responsibilities of the development and operations teams.

Start with a clear separation between application data and search data. Build a controlled search service, define explicit index mappings, use background indexing, make indexing idempotent, and protect the OpenSearch cluster behind appropriate network and authorization boundaries.

For production, capacity planning, monitoring, backups, shard management, security, and recovery should be treated as part of the application architecture rather than afterthoughts.

The key decision is not whether OpenSearch can perform application search. It can. The more important question is whether your team is prepared to operate the search infrastructure reliably at the scale and availability your application requires.