Bring your own dense vector embeddings to Elasticsearch
This tutorial demonstrates how to index documents that already have dense vector embeddings into Elasticsearch. You’ll also learn the syntax for searching these documents using a knn query.
You’ll find links at the end of this tutorial for more information about deploying a text embedding model in Elasticsearch, so you can generate embeddings for queries on the fly.
This is an advanced use case. Refer to Semantic search for an overview of your options for semantic search with Elasticsearch.
Step 1: Create an index with dense_vector mapping
Each document in our simple dataset will have:
- A review: stored in a
review_textfield -
An embedding of that review: stored in a
review_vectorfield- The
review_vectorfield is defined as adense_vectordata type.
- The
The dense_vector type automatically uses int8_hnsw quantization by default to reduce the memory footprint required when searching float vectors. Learn more about balancing performance and accuracy in Dense vector quantization.
resp = client.indices.create(
index="amazon-reviews",
mappings={
"properties": {
"review_vector": {
"type": "dense_vector",
"dims": 8,
"index": True,
"similarity": "cosine"
},
"review_text": {
"type": "text"
}
}
},
)
print(resp) const response = await client.indices.create({
index: "amazon-reviews",
mappings: {
properties: {
review_vector: {
type: "dense_vector",
dims: 8,
index: true,
similarity: "cosine",
},
review_text: {
type: "text",
},
},
},
});
console.log(response); PUT /amazon-reviews
{
"mappings": {
"properties": {
"review_vector": {
"type": "dense_vector",
"dims": 8,
"index": true,
"similarity": "cosine"
},
"review_text": {
"type": "text"
}
}
}
} | The | |
| The | |
| The |
Step 2: Index documents with embeddings
Index a single document
First, index a single document to understand the document structure.
resp = client.index(
index="amazon-reviews",
id="1",
document={
"review_text": "This product is lifechanging! I'm telling all my friends about it.",
"review_vector": [
0.1,
0.2,
0.3,
0.4,
0.5,
0.6,
0.7,
0.8
]
},
)
print(resp) const response = await client.index({
index: "amazon-reviews",
id: 1,
document: {
review_text:
"This product is lifechanging! I'm telling all my friends about it.",
review_vector: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
},
});
console.log(response); PUT /amazon-reviews/_doc/1
{
"review_text": "This product is lifechanging! I'm telling all my friends about it.",
"review_vector": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]
} | The size of the |
Bulk index multiple documents
In a production scenario, you’ll want to index many documents at once using the _bulk endpoint.
Here’s an example of indexing multiple documents in a single _bulk request.
resp = client.bulk(
operations=[
{
"index": {
"_index": "amazon-reviews",
"_id": "2"
}
},
{
"review_text": "This product is amazing! I love it.",
"review_vector": [
0.1,
0.2,
0.3,
0.4,
0.5,
0.6,
0.7,
0.8
]
},
{
"index": {
"_index": "amazon-reviews",
"_id": "3"
}
},
{
"review_text": "This product is terrible. I hate it.",
"review_vector": [
0.8,
0.7,
0.6,
0.5,
0.4,
0.3,
0.2,
0.1
]
},
{
"index": {
"_index": "amazon-reviews",
"_id": "4"
}
},
{
"review_text": "This product is great. I can do anything with it.",
"review_vector": [
0.1,
0.2,
0.3,
0.4,
0.5,
0.6,
0.7,
0.8
]
},
{
"index": {
"_index": "amazon-reviews",
"_id": "5"
}
},
{
"review_text": "This product has ruined my life and the lives of my family and friends.",
"review_vector": [
0.8,
0.7,
0.6,
0.5,
0.4,
0.3,
0.2,
0.1
]
}
],
)
print(resp) const response = await client.bulk({
operations: [
{
index: {
_index: "amazon-reviews",
_id: "2",
},
},
{
review_text: "This product is amazing! I love it.",
review_vector: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
},
{
index: {
_index: "amazon-reviews",
_id: "3",
},
},
{
review_text: "This product is terrible. I hate it.",
review_vector: [0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1],
},
{
index: {
_index: "amazon-reviews",
_id: "4",
},
},
{
review_text: "This product is great. I can do anything with it.",
review_vector: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
},
{
index: {
_index: "amazon-reviews",
_id: "5",
},
},
{
review_text:
"This product has ruined my life and the lives of my family and friends.",
review_vector: [0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1],
},
],
});
console.log(response); POST /_bulk
{ "index": { "_index": "amazon-reviews", "_id": "2" } }
{ "review_text": "This product is amazing! I love it.", "review_vector": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8] }
{ "index": { "_index": "amazon-reviews", "_id": "3" } }
{ "review_text": "This product is terrible. I hate it.", "review_vector": [0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1] }
{ "index": { "_index": "amazon-reviews", "_id": "4" } }
{ "review_text": "This product is great. I can do anything with it.", "review_vector": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8] }
{ "index": { "_index": "amazon-reviews", "_id": "5" } }
{ "review_text": "This product has ruined my life and the lives of my family and friends.", "review_vector": [0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1] } Step 3: Search documents with embeddings
Now you can query these document vectors using a knn retriever. knn is a type of vector search, which finds the k most similar documents to a query vector. Here we’re simply using a raw vector for the query text, for demonstration purposes.
resp = client.search(
index="amazon-reviews",
retriever={
"knn": {
"field": "review_vector",
"query_vector": [
0.1,
0.2,
0.3,
0.4,
0.5,
0.6,
0.7,
0.8
],
"k": 2,
"num_candidates": 5
}
},
)
print(resp) const response = await client.search({
index: "amazon-reviews",
retriever: {
knn: {
field: "review_vector",
query_vector: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
k: 2,
num_candidates: 5,
},
},
});
console.log(response); POST /amazon-reviews/_search
{
"retriever": {
"knn": {
"field": "review_vector",
"query_vector": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
"k": 2,
"num_candidates": 5
}
}
} | In this simple example, we’re sending a raw vector as the query text. In a real-world scenario, you’ll need to generate vectors for queries using an embedding model. | |
| The | |
| The |
Learn more
In this simple example, we’re sending a raw vector for the query text. In a real-world scenario you won’t know the query text ahead of time. You’ll need to generate query vectors, on the fly, using the same embedding model that generated the document vectors.
For this you’ll need to deploy a text embedding model in Elasticsearch and use the query_vector_builder parameter. Alternatively, you can generate vectors client-side and send them directly with the search request.
Learn how to use a deployed text embedding model for semantic search.
If you’re just getting started with vector search in Elasticsearch, refer to Semantic search.
© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/bring-your-own-vectors.html