Master Elasticsearch Vector Search: A Step‑by‑Step Neural Search Tutorial
This tutorial walks you through installing Elasticsearch 8.x, generating sentence embeddings with Python, creating a dense_vector index, bulk‑loading documents, and performing both exact and approximate k‑nearest‑neighbor queries using script_score and the built‑in knn API.
Overview
This guide explains how to enable and use vector (neural) search in Elasticsearch 8.x, covering the full end‑to‑end workflow from downloading the server to executing k‑NN queries.
1. Install Elasticsearch
Download Elasticsearch 8.5.3 (or any 8.x release) from the official download page and verify the SHA/ASC signatures. Ensure Java JDK 17+ is installed, then start the node with bin/elasticsearch. Security is disabled for the tutorial by setting xpack.security.enabled: false in elasticsearch.yml and restarting.
2. Generate Embeddings
Use a Python script based on sentence_transformers (model all‑MiniLM‑L6‑v2) to convert raw text into 384‑dimensional dense vectors. The script reads a TSV file of documents, encodes them in batches, and writes the vectors to an output file.
from sentence_transformers import SentenceTransformer
import torch, sys, itertools, time
BATCH_SIZE = 100
MODEL_NAME = 'all-MiniLM-L6-v2'
model = SentenceTransformer(MODEL_NAME)
if torch.cuda.is_available():
model = model.to('cuda')
def batch_encode_to_vectors(in_path, out_path):
with open(in_path, 'r') as docs, open(out_path, 'w+') as out:
for n, lines in enumerate(iter(lambda: tuple(itertools.islice(docs, BATCH_SIZE)), ())):
vectors = model.encode(lines, show_progress_bar=True)
for v in vectors:
out.write(','.join(map(str, v)) + '
')
def main():
batch_encode_to_vectors(sys.argv[1], sys.argv[2])
if __name__ == '__main__':
main()Run the script:
python batch-sentence-transformers.py ./example_input/documents_10k.tsv ./example_output/vector_documents_10k.tsv3. Create a Dense‑Vector Index
Define an index with a dense_vector field (384 dimensions, indexed, cosine similarity) and two text fields. Example request:
curl -XPUT http://localhost:9200/neural_index -H 'Content-Type: application/json' -d '{
"mappings": {
"properties": {
"general_text_vector": {"type": "dense_vector", "dims": 384, "index": true, "similarity": "cosine"},
"general_text": {"type": "text"},
"color": {"type": "text"}
}
}
}'Check the mapping with curl -XGET http://localhost:9200/neural_index.
4. Index Documents
Combine the original text file and the generated vectors, optionally add a random color field, and bulk‑index the data using the Python Elasticsearch client. The script reads both files, builds JSON documents, and sends them in batches of 1 000.
import sys, time, random
from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk
ELASTIC_ADDRESS = 'http://localhost:9200'
INDEX_NAME = 'neural_index'
BATCH_SIZE = 1000
def index_documents(txt_path, vec_path):
client = Elasticsearch([ELASTIC_ADDRESS])
docs = []
with open(txt_path, 'r') as txt_f, open(vec_path, 'r') as vec_f:
for i, (doc, vec_str) in enumerate(zip(txt_f, vec_f)):
vector = [float(v) for v in vec_str.split(',')]
color = random.choice(['red','green','white','black'])
docs.append({"_id": str(i), "general_text": doc, "general_text_vector": vector, "color": color})
if i % BATCH_SIZE == 0 and i != 0:
bulk(client, docs, index=INDEX_NAME)
docs = []
if docs:
bulk(client, docs, index=INDEX_NAME)
print('Indexing finished')
if __name__ == '__main__':
index_documents(sys.argv[1], sys.argv[2])Run the indexer:
python indexer_elastic.py ./example_input/documents_10k.tsv ./example_output/vector_documents_10k.tsv5. Search with Vectors
Two query styles are demonstrated:
Exact k‑NN (script_score) : Use a script_score query that computes cosine similarity between a query vector and the stored general_text_vector.
Approximate k‑NN : Use the built‑in knn option (HNSW) with parameters k, num_candidates, and optional filter clauses.
Example exact query:
curl -XPOST http://localhost:9200/neural_index/_search -H 'Content-Type: application/json' -d '{
"query": {
"script_score": {
"query": {"match_all": {}},
"script": {
"source": "cosineSimilarity(params.queryVector, 'general_text_vector') + 1.0",
"params": {"queryVector": [ -0.009, -0.072, ... ]}
}
}
}
}'Example approximate query with pre‑filter on color:
curl -XPOST http://localhost:9200/neural_index/_search -H 'Content-Type: application/json' -d '{
"knn": {
"field": "general_text_vector",
"query_vector": [ -0.009, -0.072, ... ],
"k": 3,
"num_candidates": 10,
"filter": {"term": {"color": "white"}}
},
"_source": false,
"fields": ["color"]
}'Mixed queries (text match + knn) are also possible, allowing hybrid relevance scoring.
Limitations and Open Issues
Current dense_vector fields cannot be sorted, aggregated, or used in nested mappings, and have cardinality limits (1024 indexed, 2048 non‑indexed vectors). Ongoing improvements are tracked in the Elasticsearch GitHub issue #84324.
Conclusion
The tutorial demonstrates how to set up neural search in Elasticsearch, generate embeddings with Python, index large document collections, and perform both exact and approximate vector queries. Future work includes multi‑value support, re‑ranking enhancements, and tighter integration with transformer models.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
dbaplus Community
Enterprise-level professional community for Database, BigData, and AIOps. Daily original articles, weekly online tech talks, monthly offline salons, and quarterly XCOPS&DAMS conferences—delivered by industry experts.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
