Resolve missing or unexpected kNN search results
This page provides a checklist for diagnosing kNN searches that fail, return no results, or do not return the document you expect. The checks cover stored embeddings, field mappings, model compatibility, and a test query to help you identify the cause of the issue.
- A kNN search fails.
- A kNN search returns no results.
- A kNN search does not return the expected document.
Elasticsearch can return a successful indexing response even when documents have no vector that a kNN search can use. This can happen when the ingest pipeline that contains the inference processor isn't applied to the indexing request, or when the inference processor is configured to ignore processor failures or missing input fields.
Use this checklist to diagnose the problem:
- Check that the document has embeddings.
- Check that the field mapping supports kNN search.
- Check that indexing and search use the same model.
- Check that search returns the expected document.
Confirm that the document contains embeddings in the expected field.
Use the example for your field type. For a semantic_text field, select your deployment type or the Elastic Stack version in which the index was created. Upgrading Elastic Stack doesn't change this behavior for existing indices.
Retrieve the document by ID and include only the embedding field. Replace my-index and 1 with the values for your document:
GET my-index/_doc/1?_source_includes=embedding
A stored vector appears in _source as an array of numbers.
Example response
{
"_index": "my-index",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"embedding": [
-0.026611328,
0.045166016,
-0.006439209,
...
-0.036621094
]
}
}
- The stored 1024-dimension vector. The example omits most values.
Include the embeddings in _source:
POST my-index/_search
{
"_source": {
"exclude_vectors": false
},
"query": {
"ids": {
"values": ["1"]
}
}
}
- Includes the stored embeddings in
_source. Vector data is excluded by default. - Identifies the document to check. Replace
1with the ID of a document you indexed.
Stored embeddings appear under _inference_fields in _source.
Example response
{
"took": 35,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "my-index",
"_id": "1",
"_score": 1,
"_source": {
"content": "Paris is the capital of France.",
"_inference_fields": {
"content": {
"inference": {
"inference_id": ".jina-embeddings-v5-text-small",
"model_settings": {
"service": "elastic",
"task_type": "text_embedding",
"dimensions": 1024,
"similarity": "cosine",
"element_type": "float"
},
"chunks": {
"content": [
{
"start_offset": 0,
"end_offset": 31,
"embeddings": [
-0.026611328,
0.045166016,
-0.006439209,
...
-0.036621094
]
}
]
}
}
}
}
}
}
]
}
}
- The stored embedding for this text chunk. The example omits most values from the 1024-dimension vector.
Request the internal inference fields:
POST my-index/_search
{
"query": {
"ids": {
"values": ["1"]
}
},
"fields": ["_inference_fields"]
}
- Identifies the document to check. Replace
1with the ID of a document you indexed. - Requests the internal inference data, including the stored embeddings.
Stored embeddings appear under _inference_fields in _source.
Example response
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "my-index",
"_id": "1",
"_score": 1,
"_source": {
"content": "Paris is the capital of France.",
"_inference_fields": {
"content": {
"inference": {
"inference_id": ".multilingual-e5-small-elasticsearch",
"model_settings": {
"service": "elasticsearch",
"task_type": "text_embedding",
"dimensions": 384,
"similarity": "cosine",
"element_type": "float"
},
"chunks": {
"content": [
{
"start_offset": 0,
"end_offset": 31,
"embeddings": [
0.007674215,
-0.0059343106,
0.023091488,
...
0.07972942
]
}
]
}
}
}
}
}
}
]
}
}
- The stored 384-dimension embedding. The example omits most values.
If the expected field is missing, the ingest pipeline might not have run, or the inference processor might have failed. Learn more about how Elasticsearch handles processor failures in Handling pipeline failures.
Confirm that the field mapping supports kNN search.
The field mapping controls how Elasticsearch stores and searches embeddings. A kNN search can search:
- A
dense_vectorfield withindex: true. - A
semantic_textfield that uses a dense embedding model.
It can't search a sparse_vector field or a semantic_text field that uses a sparse embedding model such as ELSER. Use a sparse_vector query or a match query on the semantic_text field instead.
Use the example for your field type:
Retrieve the index mapping and locate the dense_vector field under mappings.properties:
GET my-index/_mapping
Confirm the following:
typeisdense_vector.indexistrue. A kNN search can't run on a field withindex: false.dimsmatches the number of dimensions in the query vectors.
Example response
{
"my-index": {
"mappings": {
"properties": {
"embedding": {
"type": "dense_vector",
"dims": 1024,
"index": true,
"similarity": "cosine",
"index_options": {
"type": "bbq_disk",
"cluster_size": 384,
"flat_index_threshold": -1,
"default_visit_percentage": 0,
"rescore_vector": {
"oversample": 3
},
"bits": 4
}
},
"content": {
"type": "text"
}
}
}
}
}
- Confirms that the field stores dense vectors.
- The number of dimensions in each stored vector. Query vectors must have the same number of dimensions.
- Confirms that the field is indexed and supports kNN search.
Retrieve the index mapping and locate the semantic_text field under mappings.properties:
GET my-index/_mapping
Confirm the following:
typeissemantic_text.model_settings.task_typeisn'tsparse_embedding, which isn't compatible with kNN search.
Example response
{
"my-index": {
"mappings": {
"properties": {
"content": {
"type": "semantic_text",
"inference_id": ".jina-embeddings-v5-text-small",
"model_settings": {
"service": "elastic",
"task_type": "text_embedding",
"dimensions": 1024,
"similarity": "cosine",
"element_type": "float"
}
}
}
}
}
}
- Confirms that the field is a
semantic_textfield. - Confirms that the field uses a dense text embedding model that supports kNN search.
Before you search, confirm which model generated the indexed vectors. The query vectors must come from the same model because vectors from different models aren't comparable, even when they have the same number of dimensions.
Use the example for your field type:
A dense_vector field doesn't record which model generated its vectors. If an inference processor generated the document embeddings, retrieve the ingest pipeline that processed the document:
GET _ingest/pipeline/my-pipeline
Example response
{
"my-pipeline": {
"created_date_millis": 1793790532176,
"processors": [
{
"inference": {
"input_output": {
"input_field": "content",
"output_field": "embedding"
},
"model_id": ".jina-embeddings-v5-text-small"
}
}
],
"modified_date_millis": 1793790532176
}
}
- The inference endpoint that generated the document embeddings.
Check that the inference endpoint is still available. Use the model_id from the pipeline, for example:
GET _inference/.jina-embeddings-v5-text-small
If model_id refers to a trained model instead of an inference endpoint, check the model deployment:
GET _ml/trained_models/my-model/_stats
Use the same model to generate the query vector.
If you generated the vectors outside Elasticsearch, check the configuration of the application that generated them. Elasticsearch can't determine the model from the stored vectors.
Select your deployment type or the Elastic Stack version in which the index was created:
Retrieve a document and include its stored embeddings. Replace my-index with your index name and 1 with the document ID:
POST my-index/_search
{
"_source": {
"exclude_vectors": false
},
"query": {
"ids": {
"values": ["1"]
}
}
}
Example response
{
"took": 35,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "my-index",
"_id": "1",
"_score": 1,
"_source": {
"content": "Paris is the capital of France.",
"_inference_fields": {
"content": {
"inference": {
"inference_id": ".jina-embeddings-v5-text-small",
"model_settings": {
"service": "elastic",
"task_type": "text_embedding",
"dimensions": 1024,
"similarity": "cosine",
"element_type": "float"
},
"chunks": {
"content": [
{
"start_offset": 0,
"end_offset": 31,
"embeddings": [
-0.026611328,
0.045166016,
-0.006439209,
...
-0.036621094
]
}
]
}
}
}
}
}
}
]
}
}
- The inference endpoint that generated the stored embedding.
Check that the inference endpoint is still available. Use the inference_id from the document, for example:
GET _inference/.jina-embeddings-v5-text-small
Use the same model to generate the query vector.
Request the internal inference fields for a document. Replace my-index with your index name and 1 with the document ID:
POST my-index/_search
{
"query": {
"ids": {
"values": ["1"]
}
},
"fields": ["_inference_fields"]
}
Example response
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "my-index",
"_id": "1",
"_score": 1,
"_source": {
"content": "Paris is the capital of France.",
"_inference_fields": {
"content": {
"inference": {
"inference_id": ".multilingual-e5-small-elasticsearch",
"model_settings": {
"service": "elasticsearch",
"task_type": "text_embedding",
"dimensions": 384,
"similarity": "cosine",
"element_type": "float"
},
"chunks": {
"content": [
{
"start_offset": 0,
"end_offset": 31,
"embeddings": [
0.007674215,
-0.0059343106,
0.023091488,
...
0.07972942
]
}
]
}
}
}
}
}
}
]
}
}
- The inference endpoint that generated the stored embedding.
Check that the inference endpoint is still available. Use the inference_id from the document, for example:
GET _inference/.multilingual-e5-small-elasticsearch
Use the same model to generate the query vector.
Search with text that you know is in the index, and confirm that the document containing that text comes back first.
Use the example for your field type:
POST my-index/_search
{
"knn": {
"field": "embedding",
"k": 5,
"num_candidates": 50,
"query_vector_builder": {
"text_embedding": {
"model_id": ".jina-embeddings-v5-text-small",
"model_text": "Paris is the capital of France."
}
}
}
}
- Text that you know appears verbatim in a document you indexed.
Example response
{
"took": 292,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.89348686,
"hits": [
{
"_index": "my-index",
"_id": "1",
"_score": 0.89348686,
"_source": {
"content": "Paris is the capital of France."
}
}
]
}
}
- The high
_scoreindicates a strong match. - The expected document is the top result.
POST my-index/_search
{
"query": {
"knn": {
"field": "content",
"k": 1,
"num_candidates": 10,
"query_vector_builder": {
"text_embedding": {
"model_text": "Paris is the capital of France."
}
}
}
}
}
- Text that you know appears verbatim in a document you indexed.
Example response
{
"took": 113,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.8935028,
"hits": [
{
"_index": "my-index",
"_id": "1",
"_score": 0.8935028,
"_source": {
"content": "Paris is the capital of France."
}
}
]
}
}
- The high
_scoreindicates a strong match. - The expected document is the top result.