Bring your own dense vector embeddings to Elasticsearch
editBring your own dense vector embeddings to Elasticsearch
editThis 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
editEach 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
editIndex a single document
editFirst, 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]
}
Bulk index multiple documents
editIn 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
editNow 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
editIn 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.