OpenSearch integration reference

Use these options and properties to configure the OpenSearch integration, including index options, restrictions, index examples, and configuration settings. For setup instructions, see Integrate OpenSearch with Hyper-Converged Database (HCD).

Supported versions

The HCD OpenSearch integration supports OpenSearch versions 3.7.x, 3.8.x, and 3.9.x.

Index options

Pass all options as string values inside WITH OPTIONS = { …​ }.

Naming and lifecycle

The options that control the name and initial build behavior of the OpenSearch index:

Option Default Description

indexName

hcd_<keyspace>_<table>

Name of the OpenSearch index to create or use. Must be all lowercase, must not start with _ or -, and must not contain spaces, commas, or the characters : " * + / \ | ? # > <.

createIndexIfNotExists

true

When true, HCD automatically creates the OpenSearch index on CREATE INDEX. Set to false when the index is pre-provisioned externally.

skipBuildIfTableNotEmpty

false

When true, HCD skips the initial SSTable scan even when the table already contains data. HCD indexes only live writes made after CREATE INDEX. Useful when you want to backfill separately or when existing data is not needed in OpenSearch.

Column projection

The options that control which columns are replicated to OpenSearch:

Option Default Description

target

(none)

Columns specified between the parentheses in CREATE CUSTOM INDEX …​ ON table (col1, col2). CQL populates this automatically; do not set it explicitly inside WITH OPTIONS. HCD combines this with columnsToIndex to determine the final column projection.

columnsToIndex

(all columns)

Comma-separated list of non-primary-key columns to replicate to OpenSearch. Primary key columns are always included regardless of this setting. Omit to index every column.

JSON field expansion

Use these options for tables that store a complete JSON document verbatim in a single text column alongside auxiliary query columns. They let HCD expand that JSON document into individual top-level OpenSearch fields so every property is searchable and mappable. The options that control JSON field expansion:

Option Default Description

unpackJsonFields

(none)

Comma-separated list of column names whose values contain a serialized JSON object. HCD removes each listed column from the document and merges its top-level properties at the root of the OpenSearch document. HCD validates column names against the table schema at CREATE INDEX time.

When specified, set applyDefaultSchema to false (or set applyCustomSchema=true), because HCD cannot derive a meaningful field mapping when a column holds a raw JSON value. A malformed JSON value is a fatal per-row error. HCD does not write a document to OpenSearch.

propertiesFromJsonFields

(all properties)

Comma-separated list of JSON property names to keep after expansion. When specified, HCD merges only the listed properties into the root document and discards the rest. When empty (the default), HCD includes every property from the expanded JSON. Only meaningful when unpackJsonFields is also set.

Sharding and replication

The options that control the number of primary and replica shards HCD creates for the index on OpenSearch, when createIndexIfNotExists is true:

Option Default Description

numShards

1

The number of primary shards for the OpenSearch index. Increase this value for large indexes where a single shard becomes a bottleneck. You cannot change this value after you create the index. Must be a positive integer.

numReplicas

0

The number of replica shards per primary shard. Use on single-node OpenSearch deployments. Set to 1 or higher for high availability. Requires at least numReplicas + 1 OpenSearch nodes. Must be a non-negative integer.

Non-primary replica indexing

The option that controls whether non-primary HCD replicas participate in replication:

Option Default Description

indexNonPrimaryReplicas

true

When true, every HCD replica independently processes each mutation and row during the initial build and submits it to OpenSearch. OpenSearch deduplicates using external versioning so each row appears exactly once, at the cost of replication-factor reads. Set to false so that only the primary replica processes rows, which avoids duplicate work. With false, HCD does not index rows held exclusively by a non-primary replica until a rebuild or until that replica becomes primary.

Field mapping (schema)

The options that control how column types are mapped to OpenSearch field types, which apply only when createIndexIfNotExists is true:

Option Default Description

applyDefaultSchema

true

When true, HCD derives the OpenSearch field mappings from the CQL table schema. For example, int → integer, text → text with a .keyword sub-field. Set to false to suppress the automatic mapping entirely.

applyCustomSchema

false

When true, HCD uses the mapping in customMappingsJson instead of the CQL-derived defaults. You must set both applyCustomSchema: true and provide a value for customMappingsJson.

customMappingsJson

(none)

A JSON string containing a complete OpenSearch type mapping object. The value of the "mappings" key in a Create Index request body. Requires applyCustomSchema: true.

The three mapping modes are mutually exclusive and evaluated in priority order:

Priority Condition Behavior

1

applyCustomSchema=true and customMappingsJson is set

HCD sends the supplied JSON mapping verbatim.

2

applyDefaultSchema=true (default)

HCD derives the mapping from the CQL table schema.

3

Both false

HCD sends no mapping. OpenSearch applies a matching index template if one exists.

Tables that cannot be indexed

CREATE CUSTOM INDEX raises InvalidRequestException and leaves the schema untouched for the following table types:

  • A table that already has an OpenSearchIndex. Only one OpenSearch index is allowed per table.

  • Tables with static columns. A static column applies to every row in a partition, which is incompatible with the per-row replication model.

  • Tables with counter columns. Counter mutations use a different write path that the replicator does not capture.

  • Tables with dynamic data maskings (DDM) applied to columns. Unless you set -Dcassandra.replicator.allow_exporting_masked_columns=true (default false), HCD rejects index creation on tables with masked columns. HCD applies masking only at the CQL result-set layer, so an index on a masked table exports raw column values. HCD also rejects ALTER TABLE …​ MASKED WITH on an already-indexed table. Drop the index before masking a column, or drop the masks before creating the index.

    If a race condition adds masked columns to an already-indexed table, or if you set allow_exporting_masked_columns to false after you create the index, HCD suspends processing for that table until you drop the masks.

    Querying an indexed table that has masked columns using expr(…​) also requires the UNMASK permission, because the search service evaluates predicates and computes aggregations over unmasked data.

Index examples

The following examples show common CREATE CUSTOM INDEX configurations for different deployment scenarios:

High-availability production index

Three shards spread search load; one replica copy per shard provides redundancy. Index only the columns needed for search to reduce storage overhead.

CREATE CUSTOM INDEX IF NOT EXISTS articles_search
ON blog.articles ()
USING 'OpenSearchIndex'
WITH OPTIONS = {
    'indexName':              'articles-search',
    'createIndexIfNotExists': 'true',
    'numShards':              '8',
    'numReplicas':            '1',
    'columnsToIndex':         'title,body,tags'
};

This configuration requires at least two OpenSearch nodes (one primary plus one replica per shard).

Custom field mappings

Override the CQL-derived schema with a custom OpenSearch mapping. This is useful when you need specific analyzers, field types, or sub-fields that the automatic mapping does not produce.

CREATE CUSTOM INDEX IF NOT EXISTS products_search
ON store.products ()
USING 'OpenSearchIndex'
WITH OPTIONS = {
    'indexName':          'products-search',
    'applyCustomSchema':  'true',
    'customMappingsJson': '{
        "properties": {
            "id":          { "type": "keyword" },
            "name":        { "type": "text", "analyzer": "english" },
            "price":       { "type": "double" },
            "description": { "type": "text" }
        }
    }'
};

The customMappingsJson value must be a single-line JSON string inside a CQL string literal. Escape inner single quotes by doubling them ('').

JSON field unpacking (Data API schema)

Tables that the DataStax Data API manages store the full JSON document in a doc_json text column alongside auxiliary shredded columns. Use unpackJsonFields to expand the document’s properties into individual OpenSearch fields, and propertiesFromJsonFields to index only the subset you need:

CREATE CUSTOM INDEX IF NOT EXISTS products_search
ON store.products (doc_json)
USING 'OpenSearchIndex'
WITH OPTIONS = {
    'indexName':                 'products-search',
    'createIndexIfNotExists':    'true',
    'applyCustomSchema':         'true',
    'customMappingsJson':        '{
        "properties": {
            "name":  { "type": "text", "analyzer": "english" },
            "price": { "type": "double" }
        }
    }',
    'unpackJsonFields':          'doc_json',
    'propertiesFromJsonFields':  'name,price'
};

For a row with doc_json = '{"name":"Widget","price":9.99,"internal_id":"x42"}', HCD removes the doc_json column, expands it, keeps only name and price, and writes the OpenSearch document {"key": {…​}, "name": "Widget", "price": 9.99}. Omit propertiesFromJsonFields to merge every property from the JSON.

Skip initial backfill

Index only writes made after CREATE INDEX, leaving pre-existing rows out of OpenSearch until you run a separate backfill:

CREATE CUSTOM INDEX IF NOT EXISTS events_search
ON analytics.events ()
USING 'OpenSearchIndex'
WITH OPTIONS = {
    'indexName':                'events-search',
    'skipBuildIfTableNotEmpty': 'true',
    'numShards':                '5',
    'numReplicas':              '0'
};

Pre-provisioned index

When you manage the OpenSearch index externally, tell HCD not to create it:

CREATE CUSTOM INDEX IF NOT EXISTS orders_search
ON commerce.orders ()
USING 'OpenSearchIndex'
WITH OPTIONS = {
    'indexName':              'orders-search',
    'createIndexIfNotExists': 'false'
};

Defer mapping to an OpenSearch index template

Set applyDefaultSchema=false and omit applyCustomSchema and customMappingsJson to send the Create Index request with no mappings body. OpenSearch then applies any composable index template whose index_patterns matches the index name.

Use this approach when:

  • You manage the mapping outside HCD. For example, an operations team or a shared OpenSearch template library manages it.

  • You need analyzers, token filters, or index settings that HCD’s automatic mapping does not support.

  • The same template should apply consistently across multiple environments.

    1. Create the template in OpenSearch (once, before any CREATE INDEX):

      PUT _index_template/articles-template
      {
        "index_patterns": ["articles-search"],
        "template": {
          "settings": {
            "number_of_shards": 3,
            "number_of_replicas": 1
          },
          "mappings": {
            "properties": {
              "title":        { "type": "text", "analyzer": "english" },
              "body":         { "type": "text", "analyzer": "english" },
              "tags":         { "type": "keyword" },
              "published_at": { "type": "date" }
            }
          }
        }
      }
    2. Create the CQL index with both schema flags off. HCD creates the index without a mappings body and OpenSearch applies the template automatically:

      CREATE CUSTOM INDEX IF NOT EXISTS articles_search
      ON blog.articles ()
      USING 'OpenSearchIndex'
      WITH OPTIONS = {
          'indexName':          'articles-search',
          'applyDefaultSchema': 'false'
      };

If you also set numShards or numReplicas in WITH OPTIONS, HCD includes them in the Create Index settings block and they override any matching template values. Omit them to let the template control all settings.

Configuration

You can provide settings as JVM system properties, environment variables, or cassandra.yaml keys.

When HCD is started with HCDConfigurationLoader (the default), you can place all OpenSearch settings in the hcd: top-level section of cassandra.yaml. For an annotated cassandra.yaml example covering every available setting, see OpenSearch settings in cassandra.yaml.

System properties take precedence over environment variables, which take precedence over cassandra.yaml values, which take precedence over built-in defaults.

OpenSearch connection

The properties that configure the connection to the OpenSearch cluster:

Property Environment variable Default Description

cassandra.opensearch.addresses

CASSANDRA_OPENSEARCH_ADDRESSES

http://localhost:9200

Comma-separated list of OpenSearch server URLs.

cassandra.opensearch.compression.enabled

CASSANDRA_OPENSEARCH_COMPRESSION_ENABLED

true

Enable GZIP compression on outgoing requests (request body and Accept-Encoding header). Disable when the OpenSearch cluster does not support compressed requests.

cassandra.opensearch.index_retry.max_retries

CASSANDRA_OPENSEARCH_INDEX_RETRY_MAX_RETRIES

3

Maximum retry attempts for index operations. Set to -1 for unlimited retries.

cassandra.opensearch.index_retry.initial_interval

CASSANDRA_OPENSEARCH_INDEX_RETRY_INITIAL_INTERVAL

1s

Initial retry delay.

cassandra.opensearch.index_retry.max_interval

CASSANDRA_OPENSEARCH_INDEX_RETRY_MAX_INTERVAL

30s

Maximum retry delay (exponential backoff cap).

Mutation processing

The properties that tune the internal mutation processing pipeline:

Property Environment variable Default Description

cassandra.opensearch.processing.mutation_timeout

CASSANDRA_OPENSEARCH_PROCESSING_MUTATION_TIMEOUT

60s

Timeout for mutation processing.

cassandra.opensearch.processing.mutation_process_threads

CASSANDRA_OPENSEARCH_PROCESSING_MUTATION_PROCESS_THREADS

16

Number of threads for mutation processing.

cassandra.opensearch.processing.bulk_process_threads

CASSANDRA_OPENSEARCH_PROCESSING_BULK_PROCESS_THREADS

16

Number of threads for OpenSearch bulk indexing.

cassandra.opensearch.processing.bulk_batch_size

CASSANDRA_OPENSEARCH_PROCESSING_BULK_BATCH_SIZE

1000

Number of documents per bulk request.

cassandra.opensearch.processing.indexer_batch_size

CASSANDRA_OPENSEARCH_PROCESSING_INDEXER_BATCH_SIZE

10

Number of rows buffered per indexer build batch.

cassandra.opensearch.lookup.batch_size

CASSANDRA_OPENSEARCH_LOOKUP_BATCH_SIZE

100

Number of hits resolved per HCD read batch during expr(…​) row queries. Each batch becomes one SinglePartitionReadCommand.Group issued concurrently to the replicas. Minimum: 1. Decrease to reduce peak coordinator memory; increase to reduce the number of replica round-trips per page. reloadConfiguration reloads this value without a node restart.

cassandra.opensearch.processing.flush_interval

CASSANDRA_OPENSEARCH_PROCESSING_FLUSH_INTERVAL

1s

Maximum wait time before flushing a partial batch.

cassandra.opensearch.processing.remediation_timeout

CASSANDRA_OPENSEARCH_PROCESSING_REMEDIATION_TIMEOUT

1s

Timeout for remediation operations.

cassandra.opensearch.processing.bulk_retry.max_retries

CASSANDRA_OPENSEARCH_PROCESSING_BULK_RETRY_MAX_RETRIES

3

Maximum retry attempts for bulk operations.

cassandra.opensearch.processing.bulk_retry.initial_interval

CASSANDRA_OPENSEARCH_PROCESSING_BULK_RETRY_INITIAL_INTERVAL

1s

Initial retry delay for bulk operations.

cassandra.opensearch.processing.bulk_retry.max_interval

CASSANDRA_OPENSEARCH_PROCESSING_BULK_RETRY_MAX_INTERVAL

30s

Maximum retry delay for bulk operations.

cassandra.opensearch.processing.query_threads

CASSANDRA_OPENSEARCH_PROCESSING_QUERY_THREADS

16

Number of threads used to execute expr(…​) queries against OpenSearch.

cassandra.opensearch.processing.retry.max_retries

CASSANDRA_OPENSEARCH_PROCESSING_RETRY_MAX_RETRIES

unbounded

Maximum retry attempts for general processing operations (separate from bulk_retry).

cassandra.opensearch.processing.retry.initial_interval

CASSANDRA_OPENSEARCH_PROCESSING_RETRY_INITIAL_INTERVAL

1s

Initial retry delay for general processing operations.

cassandra.opensearch.processing.retry.max_interval

CASSANDRA_OPENSEARCH_PROCESSING_RETRY_MAX_INTERVAL

30s

Maximum retry delay for general processing operations.

Storage

The replicator supports two storage modes for pending mutations:

  • memory: Holds pending mutations in heap memory only. Faster, but the node loses any mutations not yet forwarded to OpenSearch if it crashes.

  • disk (default): Writes pending mutations to a durable write-ahead log on disk. Survives crashes and node restarts.

The storage properties:

Property Environment variable Default Description

cassandra.opensearch.storage.mode

CASSANDRA_OPENSEARCH_STORAGE_MODE

disk

Storage mode for pending mutations. Accepted values: memory, disk. See the mode descriptions above this table.

cassandra.opensearch.storage.directory

CASSANDRA_OPENSEARCH_STORAGE_DIRECTORY

(auto-discovered)

Directory for persistent storage (disk mode only). When empty, HCD auto-discovers the directory from HCD’s data directory configuration (typically <cassandra_data_dir>/opensearch-storage/).

cassandra.opensearch.storage.max_pending_count

CASSANDRA_OPENSEARCH_STORAGE_MAX_PENDING_COUNT

100000

Maximum number of pending mutations before HCD applies flow control and slows incoming writes.

The disk storage properties:

Property Environment variable Default Description

cassandra.opensearch.storage.memtable_byte_budget

CASSANDRA_OPENSEARCH_STORAGE_MEMTABLE_BYTE_BUDGET

536870912 (512 MiB)

Per-table memtable size limit.

cassandra.opensearch.storage.commit_log_max_file_bytes

CASSANDRA_OPENSEARCH_STORAGE_COMMIT_LOG_MAX_FILE_BYTES

8388608 (8 MiB)

Maximum commit log file size.

cassandra.opensearch.storage.commit_log_checkpoint_threshold_bytes

CASSANDRA_OPENSEARCH_STORAGE_COMMIT_LOG_CHECKPOINT_THRESHOLD_BYTES

33554432 (32 MiB)

Checkpoint trigger size.

cassandra.opensearch.storage.force_max_wait_nanos

CASSANDRA_OPENSEARCH_STORAGE_FORCE_MAX_WAIT_NANOS

1000000 (1 ms)

Fsync batching window.

cassandra.opensearch.storage.flush_when_queue_empty

CASSANDRA_OPENSEARCH_STORAGE_FLUSH_WHEN_QUEUE_EMPTY

true

Flush immediately when the queue is empty (low-latency mode).

cassandra.opensearch.storage.shared_memtable_budget

CASSANDRA_OPENSEARCH_STORAGE_SHARED_MEMTABLE_BUDGET

1073741824 (1 GiB)

Shared memory budget across all tables.

cassandra.opensearch.storage.complete_on_write

CASSANDRA_OPENSEARCH_STORAGE_COMPLETE_ON_WRITE

true

Complete startMutation futures on write to the OS page cache rather than waiting for fsync.

cassandra.opensearch.storage.completed_mutations_flush_interval_ms

CASSANDRA_OPENSEARCH_STORAGE_COMPLETED_MUTATIONS_FLUSH_INTERVAL_MS

1

Flush interval in milliseconds for completed mutations.

The replicator maintains persistent state in the following directory structure, where <storage.directory> is the configured storage directory, <keyspace> and <table> identify the HCD table being replicated, and <id> is a file identifier the replicator assigns automatically:

<storage.directory>/
├── <keyspace>/
│   └── <table>/
│       ├── manifest.json     # Current checkpoint state
│       ├── cl-<id>.log       # Commit log files (write-ahead log)
│       └── seg-<id>.dat      # Data segment files (flushed memtables)
  • Commit log: Rolling log files (cl-*.log) that record all pending mutations for crash recovery.

  • Segments: Immutable data files (seg-*.dat) containing data written from memory to disk.

  • Manifest: JSON file tracking current checkpoint state and active files.

Other system properties

The properties that control miscellaneous integration behaviors:

Property Environment variable Default Description

cassandra.replicator.allow_exporting_masked_columns

CASSANDRA_REPLICATOR_ALLOW_EXPORTING_MASKED_COLUMNS

false

Allow creating or keeping an OpenSearch index on a table with dynamically masked columns. For more information, see Tables that cannot be indexed.

cassandra.replicator.register_decommission_hook

CASSANDRA_REPLICATOR_REGISTER_DECOMMISSION_HOOK

true

When true, blocks nodetool decommission until all pending mutations for this node are sent to OpenSearch. Set to false to disable, for example during testing. For more information, see Node decommission safety.

cassandra.opensearch.query.send_result_payload

CASSANDRA_OPENSEARCH_QUERY_SEND_RESULT_PAYLOAD

true

Attach the OpenSearchIndex.numFound, isPartialResults, and aggregations custom payload to expr(…​) query responses. For more information, see Result payload. Set to false to disable.

cassandra.opensearch.query.max_agg_json_bytes

CASSANDRA_OPENSEARCH_QUERY_MAX_AGG_JSON_BYTES

1048576 (1 MiB)

Maximum size of a single aggregation’s JSON before HCD returns it as a result column.

cassandra.opensearch.query.max_agg_response_bytes

CASSANDRA_OPENSEARCH_QUERY_MAX_AGG_RESPONSE_BYTES

16777216 (16 MiB)

Maximum size of the raw OpenSearch response for a count(*) or aggregation query, checked before parsing.

Was this helpful?

Give Feedback

How can we improve the documentation?

© Copyright IBM Corporation 2026 | Privacy policy | Terms of use |  Manage Privacy Choices

Apache, Apache Cassandra, Cassandra, Apache Tomcat, Tomcat, Apache Lucene, Apache Solr, Apache Hadoop, Hadoop, Apache Pulsar, Pulsar, Apache Spark, Spark, Apache TinkerPop, TinkerPop, Apache Kafka and Kafka are either registered trademarks or trademarks of the Apache Software Foundation or its subsidiaries in Canada, the United States and/or other countries. Kubernetes is the registered trademark of the Linux Foundation.

General Inquiries: Contact IBM