Compatibility: Only available on Node.js.
Elasticsearch is a distributed, RESTful search engine optimized for speed and relevance on production-scale workloads. It supports vector search using the k-nearest neighbor (kNN) algorithm and also custom models for Natural Language Processing (NLP).
You can read more about the support of vector search in Elasticsearch here.
This guide provides a quick overview for getting started with Elasticsearch vector stores. For detailed documentation of all ElasticVectorSearch features and configurations head to the API reference.
Overview
Integration details
Installation and setup
Install packages
To use Elasticsearch vector stores, you’ll need to install the @langchain/community integration package.
LangChain.js accepts @elastic/elasticsearch as the client for Elasticsearch vectorstore. You’ll need to install it as a peer dependency.
This guide will also use OpenAI embeddings, which require you to install the @langchain/openai integration package. You can also use other supported embeddings models if you wish.
npm install @langchain/community @elastic/elasticsearch @langchain/openai @langchain/core
Setup Elasticsearch
There are three ways to get started with Elasticsearch:
Option 1: start-local (recommended for development)
The quickest way to set up Elasticsearch locally for development and testing is using the start-local script. This script sets up Elasticsearch and Kibana in Docker with a single command.
curl -fsSL https://elastic.co/start-local | sh
This script creates an elastic-start-local folder containing:
- Configuration files for Elasticsearch and Kibana
- A
.env file with connection details and credentials
After running the script, you can find your credentials in the .env file:
cd elastic-start-local
cat .env
The .env file contains ES_LOCAL_URL and ES_LOCAL_API_KEY that you can use to connect:
const config: ClientOptions = {
node: process.env.ES_LOCAL_URL ?? "http://localhost:9200",
auth: {
apiKey: process.env.ES_LOCAL_API_KEY,
},
};
To stop and start the services:
# Stop the services
./elastic-start-local/stop.sh
# Start the services
./elastic-start-local/start.sh
# Uninstall completely
./elastic-start-local/uninstall.sh
For more information, see the start-local GitHub repository.
Option 2: Docker (manual setup)
You can use the official Docker image to get started. Run a single-node Elasticsearch instance with security disabled. This is not recommended for production use.
docker run -p 9200:9200 -e "discovery.type=single-node" -e "xpack.security.enabled=false" -e "xpack.security.http.ssl.enabled=false" docker.elastic.co/elasticsearch/elasticsearch:8.17.0
Option 3: Elastic Cloud
Elastic Cloud is a managed Elasticsearch service. You can sign up for a free trial.
- Create a deployment
- Get your Cloud ID:
- In the Elastic Cloud console, click “Manage” next to your deployment
- Copy the Cloud ID and paste it into your configuration
- Create an API key:
- In the Elastic Cloud console, click “Open” next to your deployment
- In the left-hand side menu, go to “Stack Management”, then to “API Keys”
- Click “Create API key”
- Enter a name for the API key and click “Create”
- Copy the API key and paste it into your configuration
For connecting to Elastic Cloud you can read the documentation reported here for obtaining an API key.
Credentials
If you are using OpenAI embeddings for this guide, you’ll need to set your OpenAI key:
process.env.OPENAI_API_KEY = "YOUR_API_KEY";
If you want to get automated tracing of your model calls you can also set your LangSmith API key by uncommenting below:
// process.env.LANGSMITH_TRACING="true"
// process.env.LANGSMITH_API_KEY="your-api-key"
ElasticVectorSearch
The ElasticVectorSearch class provides Elasticsearch as a vector store with support for both standard vector search and hybrid search.
Instantiation
Instantiating Elasticsearch will vary depending on where your instance is hosted.
import {
ElasticVectorSearch,
type ElasticClientArgs,
} from "@langchain/community/vectorstores/elasticsearch";
import { OpenAIEmbeddings } from "@langchain/openai";
import { Client, type ClientOptions } from "@elastic/elasticsearch";
import * as fs from "node:fs";
const embeddings = new OpenAIEmbeddings({
model: "text-embedding-3-small",
});
const config: ClientOptions = {
node: process.env.ELASTIC_URL ?? "https://127.0.0.1:9200",
};
if (process.env.ELASTIC_API_KEY) {
config.auth = {
apiKey: process.env.ELASTIC_API_KEY,
};
} else if (process.env.ELASTIC_USERNAME && process.env.ELASTIC_PASSWORD) {
config.auth = {
username: process.env.ELASTIC_USERNAME,
password: process.env.ELASTIC_PASSWORD,
};
}
// Local Docker deploys require a TLS certificate
if (process.env.ELASTIC_CERT_PATH) {
config.tls = {
ca: fs.readFileSync(process.env.ELASTIC_CERT_PATH),
rejectUnauthorized: false,
}
}
const clientArgs: ElasticClientArgs = {
client: new Client(config),
indexName: process.env.ELASTIC_INDEX ?? "test_vectorstore",
};
const vectorStore = new ElasticVectorSearch(embeddings, clientArgs);
addDocuments
Add documents to the vector store.
import type { Document } from "@langchain/core/documents";
const document1: Document = {
pageContent: "The powerhouse of the cell is the mitochondria",
metadata: { source: "https://example.com" }
};
const document2: Document = {
pageContent: "Buildings are made out of brick",
metadata: { source: "https://example.com" }
};
const document3: Document = {
pageContent: "Mitochondria are made out of lipids",
metadata: { source: "https://example.com" }
};
const document4: Document = {
pageContent: "The 2024 Olympics are in Paris",
metadata: { source: "https://example.com" }
}
const documents = [document1, document2, document3, document4];
await vectorStore.addDocuments(documents, { ids: ["1", "2", "3", "4"] });
delete
Delete documents from the vector store by ID.
await vectorStore.delete({ ids: ["4"] });
similaritySearch
Perform a similarity search to find documents similar to a query.
const filter = [{
operator: "match",
field: "source",
value: "https://example.com",
}];
const similaritySearchResults = await vectorStore.similaritySearch("biology", 2, filter);
for (const doc of similaritySearchResults) {
console.log(`* ${doc.pageContent} [${JSON.stringify(doc.metadata, null)}]`);
}
* The powerhouse of the cell is the mitochondria [{"source":"https://example.com"}]
* Mitochondria are made out of lipids [{"source":"https://example.com"}]
The vector store supports Elasticsearch filter syntax operators.
similaritySearchWithScore
Perform a similarity search and return scores.
const similaritySearchWithScoreResults = await vectorStore.similaritySearchWithScore("biology", 2, filter)
for (const [doc, score] of similaritySearchWithScoreResults) {
console.log(`* [SIM=${score.toFixed(3)}] ${doc.pageContent} [${JSON.stringify(doc.metadata)}]`);
}
* [SIM=0.374] The powerhouse of the cell is the mitochondria [{"source":"https://example.com"}]
* [SIM=0.370] Mitochondria are made out of lipids [{"source":"https://example.com"}]
asRetriever
Transform the vector store into a retriever for use in chains.
const retriever = vectorStore.asRetriever({
// Optional filter
filter: filter,
k: 2,
});
await retriever.invoke("biology");
[
Document {
pageContent: 'The powerhouse of the cell is the mitochondria',
metadata: { source: 'https://example.com' },
id: undefined
},
Document {
pageContent: 'Mitochondria are made out of lipids',
metadata: { source: 'https://example.com' },
id: undefined
}
]
HybridRetrievalStrategy
Hybrid search requires Elasticsearch 8.9+ for RRF (Reciprocal Rank Fusion) support.
Hybrid search combines kNN vector search with BM25 full-text search using Reciprocal Rank Fusion (RRF) to improve search relevance. This is useful when you want to leverage both semantic similarity and keyword matching.
Configuration options
| Parameter | Type | Default | Description |
|---|
rankWindowSize | number | 100 | Number of documents to consider for RRF |
rankConstant | number | 60 | RRF constant for score normalization |
textField | string | "text" | Field to use for BM25 full-text search |
Basic usage
To enable hybrid search, pass a HybridRetrievalStrategy to the constructor:
import {
ElasticVectorSearch,
HybridRetrievalStrategy,
type ElasticClientArgs,
} from "@langchain/community/vectorstores/elasticsearch";
const hybridVectorStore = new ElasticVectorSearch(embeddings, {
client: new Client(config),
indexName: "test_hybrid_search",
strategy: new HybridRetrievalStrategy({
rankWindowSize: 100, // Number of documents to consider for RRF
rankConstant: 60, // RRF constant for score normalization
textField: "text", // Field to use for BM25 full-text search
}),
});
Once configured, hybrid search is automatically used for all similarity searches:
// This now uses hybrid search (vector + BM25 + RRF)
const results = await hybridVectorStore.similaritySearch(
"how to prevent muscle soreness while running",
5
);
Complete hybrid search example
import { Client, ClientOptions } from "@elastic/elasticsearch";
import { OpenAIEmbeddings } from "@langchain/openai";
import {
ElasticClientArgs,
ElasticVectorSearch,
HybridRetrievalStrategy,
} from "@langchain/community/vectorstores/elasticsearch";
import { Document } from "@langchain/core/documents";
// Configure Elasticsearch client
const config: ClientOptions = {
node: process.env.ES_LOCAL_URL ?? "http://127.0.0.1:9200",
};
if (process.env.ES_LOCAL_API_KEY) {
config.auth = {
apiKey: process.env.ES_LOCAL_API_KEY,
};
}
const embeddings = new OpenAIEmbeddings();
// Create vector store with hybrid search strategy
const clientArgs: ElasticClientArgs = {
client: new Client(config),
indexName: "test_hybrid_search",
strategy: new HybridRetrievalStrategy({
rankWindowSize: 100,
rankConstant: 60,
textField: "text",
}),
};
const vectorStore = new ElasticVectorSearch(embeddings, clientArgs);
// Add documents
await vectorStore.addDocuments([
new Document({
pageContent: "Running improves cardiovascular health and endurance",
metadata: { category: "fitness" },
}),
new Document({
pageContent: "Proper hydration prevents muscle cramps during exercise",
metadata: { category: "fitness" },
}),
new Document({
pageContent: "Stretching before running reduces injury risk",
metadata: { category: "fitness" },
}),
]);
// Search using hybrid (vector + BM25)
const results = await vectorStore.similaritySearch(
"how to prevent muscle soreness while running",
3
);
console.log(results);
Usage for retrieval-augmented generation
For guides on how to use this vector store for retrieval-augmented generation (RAG), see the following sections:
API reference
For detailed documentation of all ElasticVectorSearch features and configurations head to the API reference.