Exact kNN search
Exact kNN search computes similarity between the query vector and every matching document, so results are fully accurate but latency increases with corpus size. Use it for small datasets, pre-filtered subsets, or when you need precise scoring without approximate indexing. For most production workloads, prefer Approximate kNN search.
Elasticsearch supports two query methods for exact kNN search:
- Use the
dense_vectorquery for standard exact vector scoring. See an example. - Use the
script_scorequery when you need a custom scoring calculation. See an example.
First, map and index the vectors that you want to search:
Explicitly map one or more
dense_vectorfields. If you don't intend to use the field for approximate kNN, set theindexmapping option tofalse. This can significantly improve indexing speed.PUT product-index{ "mappings": { "properties": { "product-vector": { "type": "dense_vector", "dims": 5, "index": false }, "price": { "type": "long" } } } }Index your data.
POST product-index/_bulk?refresh=true{ "index": { "_id": "1" } } { "product-vector": [230.0, 300.33, -34.8988, 15.555, -200.0], "price": 1599 } { "index": { "_id": "2" } } { "product-vector": [-0.5, 100.0, -13.0, 14.8, -156.0], "price": 799 } { "index": { "_id": "3" } } { "product-vector": [0.5, 111.3, -13.0, 14.8, -156.0], "price": 1099 } ...
Use the search API to run a dense_vector query. The query scores every document that has a value for the specified vector field. To reduce the number of vectors that it scores, combine it with a filter in a bool query:
POST product-index/_search
{
"query": {
"bool": {
"must": {
"dense_vector": {
"field": "product-vector",
"query_vector": [-0.5, 90.0, -10, 14.8, -156.0]
}
},
"filter": {
"range": {
"price": {
"gte": 1000
}
}
}
}
}
}
Because product-vector uses the default float element type and is not indexed, the query uses cosine similarity by default. You can use the similarity_function parameter to select a different similarity function. For indexed fields, the query uses the similarity configured in the field mapping by default.
Use a script_score query if the dense_vector query isn't available in your Elastic Stack version. You can also use script_score when you need to customize the scoring calculation.
Specify a filter query in the script_score.query parameter to limit the number of matched documents passed to the vector function. If needed, you can use a match_all query in this parameter to match all documents. However, matching all documents can significantly increase search latency.
POST product-index/_search
{
"query": {
"script_score": {
"query": {
"bool": {
"filter": {
"range": {
"price": {
"gte": 1000
}
}
}
}
},
"script": {
"source": "cosineSimilarity(params.queryVector, 'product-vector') + 1.0",
"params": {
"queryVector": [-0.5, 90.0, -10, 14.8, -156.0]
}
}
}
}
}
The dense_vector and script_score examples can rank documents in the same order, but they don't return the same numeric scores. The dense_vector query applies the built-in score transformation for the selected similarity function. A script_score query returns the value calculated by your script, such as the cosine similarity plus 1.0 in this example.
- Tune approximate kNN search: Production guidance for vector memory, node sizing, indexing, filesystem cache, and on-disk rescoring.
- Profile kNN search: Inspect query timing and vector operation counts to diagnose slow kNN searches.
dense_vectorfield type: API reference for vector field mapping, includingindex,similarity,index_options, and quantization parameters.knnquery: API reference for theknnquery, including parameters,query_vector_builderoptions, and usage withdense_vectorandsemantic_textfields.