-v2, backfill, dual-write new documents, swap an index alias, then delete -v1 only after queries are stable.
Validated on 27 Apr 2026 • Last edited on 27 Apr 2026
DigitalOcean Managed OpenSearch for vector search uses the same managed OpenSearch engine available under Managed Databases. It bundles the k-NN, ML Commons, and Neural Search plugins for vector similarity search, hybrid vector and keyword search, and remote embedding models.
A k-NN index is a regular OpenSearch index with one or more knn_vector fields and the index.knn setting enabled. The k-NN plugin, which is enabled by default on DigitalOcean Managed OpenSearch, builds a graph index over those fields so approximate nearest-neighbor queries run in sub-linear time.
This guide covers the three decisions to make when creating a k-NN index: which engine to use, which distance function to use, and how to tune HNSW parameters.
$OS holds the base URL with auth baked in.text-embedding-3-small).OpenSearch supports three k-NN engines, each implementing HNSW. The engine is set per knn_vector field in the mapping.
| Engine | When to use |
|---|---|
| Faiss (default in 2.19) | Best general-purpose choice. High throughput at scale, supports product and scalar quantization for memory reduction, and (since k-NN 2.9) efficient filtering. |
| Lucene | Native OpenSearch HNSW with tight Lucene segment integration. Good for pure-Java operations or segment-level restores. Tops out around 10M vectors per shard. |
| NMSLIB | Deprecated. Keep only for migrating older indexes. Do not use for new workloads. |
Both Faiss and Lucene apply k-NN filters during graph traversal, so even restrictive filters return an accurate top-k. Each engine falls back to an exact scan when a filter is very selective.
The space_type determines the similarity metric and must match how your embedding model was trained.
| space_type | Similarity and use case |
|---|---|
| cosinesimil | Cosine similarity. Standard for text embeddings (OpenAI, Cohere, sentence-transformers, bge, e5, Voyage). Magnitude-invariant. |
| innerproduct | Dot product. Assumes vectors are L2-normalized. Use when your model recommends it. |
| l2 | Euclidean distance. Common for image embeddings (CLIP, OpenCLIP) and models trained with L2 loss. |
| l1 | Manhattan distance. Rare. |
If you are unsure, check your embedding model’s documentation. See the OpenSearch k-NN spaces reference for details.
HNSW has three parameters that trade recall against build time, memory, and query latency:
m: Bidirectional links per node. Larger m improves recall but increases RAM and build time. Range 8-64. Default 16.ef_construction: Build-time candidate pool size. Larger values produce a higher-quality graph at the cost of ingestion time. Range 100-512. Default 128.ef_search: Query-time candidate pool size. Set at the index level via index.knn.algo_param.ef_search or per query via method_parameters.ef_search. Default 100.Defaults are a reasonable starting point. Only tune after measuring recall on a held-out query set. A typical progression is to raise ef_search first per-query (no re-index), promote the best value to the index setting, and only touch m or ef_construction (which do require a re-index) if query-time tuning is not enough.
This example creates an index for a semantic-search workload with 1024-dimensional vectors (bge-large, GTE-large, or similar), cosine similarity, and HNSW parameters tuned for quality over build time.
curl -X PUT "$OS/documents" -H 'Content-Type: application/json' -d '{
"settings": {
"index": {
"knn": true,
"knn.algo_param.ef_search": 200,
"number_of_shards": 2,
"number_of_replicas": 1,
"refresh_interval": "30s"
}
},
"mappings": {
"properties": {
"title": { "type": "text" },
"body": { "type": "text" },
"source": { "type": "keyword" },
"created_at": { "type": "date" },
"embedding": {
"type": "knn_vector",
"dimension": 1024,
"method": {
"name": "hnsw",
"engine": "faiss",
"space_type": "cosinesimil",
"parameters": {
"m": 24,
"ef_construction": 256
}
}
}
}
}
}'A few choices worth calling out:
number_of_shards: Start with 1-2. HNSW graphs are per-shard, so more shards mean lower recall unless you raise ef_search. Only increase shards when a single shard exceeds approximately 50 million documents or 50 GiB.refresh_interval: Bumped from the default 1s to 30s to amortize HNSW segment builds. Reduces ingestion overhead meaningfully for batch indexing. Set to -1 during initial bulk loads and reset afterward.keyword and date fields alongside the vector enable filtered k-NN queries.If you have fewer than about 10,000 vectors, or you only query a subset of vectors matching a restrictive filter, exact k-NN using a script_score query is simpler and has perfect recall. Omit the method block in the mapping:
"embedding": {
"type": "knn_vector",
"dimension": 1024
}You can then query with knn_score as described in Index and Query Vectors via the OpenSearch API.
Adding a new knn_vector field to an existing index is supported with PUT <index>/_mapping. Changing the engine, dimension, or space_type of an existing field is not. To change those, create a new index and reindex:
curl -X POST "$OS/_reindex" -H 'Content-Type: application/json' -d '{
"source": { "index": "documents-v1" },
"dest": { "index": "documents-v2" }
}'-v2, backfill, dual-write new documents, swap an index alias, then delete -v1 only after queries are stable.
Try using different keywords or simplifying your search terms.