kNN Search Request
The kNN Search request performs a k-nearest neighbor (kNN) search: given a query vector, it finds the k closest vectors and returns those documents as search hits.
Note that this request uses the _knn_search API, which was deprecated in Elasticsearch 8.4 in favour of the knn option of the _search API. It is still available in 8.x, but may be removed in a future Elasticsearch version.
In order to use the kNN Search request, the searched field must be mapped as a dense_vector field with indexing enabled, for example:
import zio.elasticsearch.ElasticRequest.{createIndex, CreateIndexRequest}
import zio.elasticsearch._
val createIndexRequest: CreateIndexRequest =
createIndex(
index = IndexName("index"),
definition = """{ "mappings": { "properties": { "vectorField": { "type": "dense_vector", "dims": 3, "similarity": "l2_norm", "index": true } } } }"""
)
To create a kNN Search request do the following:
import zio.Chunk
import zio.elasticsearch.ElasticRequest.{knnSearch, KNNRequest}
// this import is required for using `IndexName`, `IndexPattern` and `MultiIndex`
import zio.elasticsearch._
import zio.elasticsearch.ElasticQuery._
val request: KNNRequest =
knnSearch(selectors = IndexName("index"), query = kNN(field = Document.vectorField, k = 2, numCandidates = 5, queryVector = Chunk(1.0, 2.0, 3.0)))
The query parameter of the knnSearch method is a kNN query.
If you want to filter the documents that can match, you can use the filter method with any query:
val requestWithFilter: KNNRequest =
knnSearch(selectors = IndexName("index"), query = kNN(field = Document.vectorField, k = 2, numCandidates = 5, queryVector = Chunk(1.0, 2.0, 3.0)))
.filter(range(Document.intField).gt(10))
If you want to change the routing, you can use the routing method:
// this import is required for using `Routing` also
import zio.elasticsearch._
val requestWithRouting: KNNRequest =
knnSearch(selectors = IndexName("index"), query = kNN(field = Document.vectorField, k = 2, numCandidates = 5, queryVector = Chunk(1.0, 2.0, 3.0)))
.routing(Routing("routing"))
If you want to create kNN Search request with IndexPattern, do the following:
val requestWithIndexPattern: KNNRequest =
knnSearch(selectors = IndexPattern("index*"), query = kNN(field = Document.vectorField, k = 2, numCandidates = 5, queryVector = Chunk(1.0, 2.0, 3.0)))
If you want to create kNN Search request with MultiIndex, do the following:
val requestWithMultiIndex: KNNRequest =
knnSearch(
selectors = MultiIndex.names(IndexName("index1"), IndexName("index2")),
query = kNN(field = Document.vectorField, k = 2, numCandidates = 5, queryVector = Chunk(1.0, 2.0, 3.0))
)
The result of executing a kNN Search request is KNNSearchResult, from which you can get the documents (or items) of the nearest neighbors:
import zio._
val result: RIO[Elasticsearch, Chunk[Document]] =
Elasticsearch.execute(request).documentAs[Document]
You can find more information about kNN Search request here.