OpenSearch’s Neural Search plugin lets you do vector search, but setting it up can feel like trying to thread a needle in the dark.
Let’s see it in action. Imagine you have a collection of product descriptions, and you want to find products similar to "a comfortable blue running shoe for marathons."
First, we need to ingest our data. This involves embedding our text into vectors.
PUT /products
{
"mappings": {
"properties": {
"description": {
"type": "text"
},
"description_vector": {
"type": "knn_vector",
"dimension": 768
}
}
}
}
Then, we add some data, including the embedded vectors. The description_vector field is where our embeddings will live.
POST /products/_doc
{
"description": "A lightweight, breathable running shoe designed for long-distance comfort.",
"description_vector": [0.1, 0.2, ..., 0.9]
}
POST /products/_doc
{
"description": "Durable athletic sneakers perfect for gym workouts and casual wear.",
"description_vector": [0.3, 0.4, ..., 0.7]
}
Now, to search, we need to embed our query "a comfortable blue running shoe for marathons" into a vector. Let’s say that vector is [0.15, 0.25, ..., 0.85].
Our search query looks like this:
GET /products/_search
{
"size": 5,
"query": {
"knn": {
"field": "description_vector",
"query_vector": [0.15, 0.25, ..., 0.85],
"k": 5
}
}
}
This query asks OpenSearch to find the 5 (k=5) nearest neighbors to our query vector in the description_vector field. The results will be documents whose vectors are closest in the multi-dimensional space.
The core problem Neural Search solves is enabling semantic similarity search. Traditional keyword search struggles with synonyms, context, and nuance. Vector search, by representing text as dense numerical vectors, captures meaning. Documents with similar meanings will have vectors close to each other in the vector space, regardless of exact word matches. The knn_vector data type and the knn query are the direct implementations of this.
The dimension in the mapping is crucial; it must match the dimensionality of the vectors generated by your embedding model. If your model outputs 768-dimensional vectors, your mapping must specify dimension: 768. Mismatches here will cause indexing or search failures. The k parameter in the knn query determines how many nearest neighbors to return.
The magic of vector search lies in the Approximate Nearest Neighbor (ANN) algorithms OpenSearch uses under the hood. Instead of a brute-force comparison against every single vector (which would be computationally prohibitive for large datasets), ANN algorithms build an index that allows for rapid, albeit approximate, retrieval of the closest vectors. This is why the knn query is significantly faster than a full scan. The specific ANN algorithm and its parameters (like m and ef_search for HNSW) can be configured to tune the trade-off between search speed and accuracy.
When you configure the knn plugin, you’re essentially telling OpenSearch how to build and query these ANN indexes. You can specify different indexing methods (like HNSW or IVF) and their associated parameters directly in the index mapping or via index settings. For example, to use HNSW with specific parameters:
PUT /products
{
"settings": {
"index": {
"knn": true,
"knn.algo_param.ef_search": 100,
"knn.algo_param.m": 16
}
},
"mappings": {
"properties": {
"description_vector": {
"type": "knn_vector",
"dimension": 768
}
}
}
}
These parameters (ef_search, m) directly influence the structure of the HNSW graph, affecting how neighbors are explored during search. Higher ef_search values generally lead to more accurate results but slower searches.
The next hurdle is often integrating a real-time embedding pipeline.