Skip to main content
兼容性:仅在 Node.js 上可用。
Elasticsearch 是一个分布式、RESTful 搜索引擎,针对生产规模工作负载的速度和相关性进行了优化。它支持使用 k-最近邻 (kNN) 算法的向量搜索,还支持 用于自然语言处理的自定义模型 (NLP)。 您可以 在此处 阅读有关 Elasticsearch 中向量搜索支持的更多信息。 本指南提供了使用 Elasticsearch 向量存储的快速概述。有关所有 ElasticVectorSearch 功能和配置的详细文档,请参阅 API 参考

概述

集成细节

安装和设置

安装包

要使用 Elasticsearch 向量存储,您需要安装 @langchain/community 集成包。 LangChain.js 接受 @elastic/elasticsearch 作为 Elasticsearch 向量存储的客户端。您需要将其作为对等依赖项安装。 本指南还将使用 OpenAI 嵌入,这需要您安装 @langchain/openai 集成包。如果您愿意,也可以使用 其他支持的嵌入模型
npm install @langchain/community @elastic/elasticsearch @langchain/openai @langchain/core

设置 Elasticsearch

可以通过三种方式开始使用 Elasticsearch:

选项 1:start-local(建议用于开发)

在本地设置 Elasticsearch 进行开发和测试的最快方法是使用 start-local 脚本。此脚本使用单个命令在 Docker 中设置 Elasticsearch 和 Kibana。
curl -fsSL https://elastic.co/start-local | sh
此脚本创建一个包含以下内容的 elastic-start-local 文件夹:
  • Elasticsearch 和 Kibana 的配置文件
  • 带有连接详细信息和凭据的 .env 文件
运行脚本后,您可以在 .env 文件中找到您的凭据:
cd elastic-start-local
cat .env
.env 文件包含 ES_LOCAL_URLES_LOCAL_API_KEY,您可以使用它们进行连接:
const config: ClientOptions = {
  node: process.env.ES_LOCAL_URL ?? "http://localhost:9200",
  auth: {
    apiKey: process.env.ES_LOCAL_API_KEY,
  },
};
要停止和启动服务:
# Stop the services
./elastic-start-local/stop.sh

# Start the services
./elastic-start-local/start.sh

# Uninstall completely
./elastic-start-local/uninstall.sh
有关更多信息,请参阅 start-local GitHub 存储库

选项 2:Docker(手动设置)

您可以使用 官方 Docker 镜像 开始。运行禁用安全性的单节点 Elasticsearch 实例。不建议用于生产环境。
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

选项 3:Elastic Cloud

Elastic Cloud 是托管的 Elasticsearch 服务。您可以注册 免费试用
  1. 创建部署
  2. 获取您的 Cloud ID:
    1. Elastic Cloud 控制台 中,单击部署旁边的“管理”
    2. 复制 Cloud ID 并将其粘贴到您的配置中
  3. 创建 API 密钥:
    1. Elastic Cloud 控制台 中,单击部署旁边的“打开”
    2. 在左侧菜单中,转到“堆栈管理”,然后转到“API 密钥”
    3. 单击“创建 API 密钥”
    4. 输入 API 密钥的名称,然后单击“创建”
    5. 复制 API 密钥并将其粘贴到您的配置中
有关连接到 Elastic Cloud 的信息,您可以阅读 此处 报告的有关获取 API 密钥的文档。

凭据

如果您在本指南中使用 OpenAI 嵌入,您还需要设置您的 OpenAI 密钥:
process.env.OPENAI_API_KEY = "YOUR_API_KEY";
如果您想获取模型调用的自动跟踪,您还可以通过取消注释以下内容来设置您的 LangSmith API 密钥:
// process.env.LANGSMITH_TRACING="true"
// process.env.LANGSMITH_API_KEY="your-api-key"

ElasticVectorSearch

ElasticVectorSearch 类将 Elasticsearch 作为向量存储提供,支持标准向量搜索和混合搜索。

实例化

实例化 Elasticsearch 会因您的实例托管位置而异。
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

向向量存储添加文档。
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"] });
[ '1', '2', '3', '4' ]

delete

按 ID 从向量存储中删除文档。
await vectorStore.delete({ ids: ["4"] });

similaritySearch

执行相似性搜索以查找与查询相似的文档。
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"}]
向量存储支持 Elasticsearch 过滤器语法 运算符。

similaritySearchWithScore

执行相似性搜索并返回分数。
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

将向量存储转换为检索器以在链中使用。
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

混合搜索需要 Elasticsearch 8.9+ 以支持 RRF(倒数排名融合)。
混合搜索使用倒数排名融合 (RRF) 将 kNN 向量搜索与 BM25 全文搜索相结合,以提高搜索相关性。当您想利用语义相似性和关键字匹配时,这很有用。

配置选项

ParameterTypeDefaultDescription
rankWindowSizenumber100考虑用于 RRF 的文档数
rankConstantnumber60用于分数归一化的 RRF 常数
textFieldstring"text"用于 BM25 全文搜索的字段

基本用法

要启用混合搜索,请将 HybridRetrievalStrategy 传递给构造函数:
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
  }),
});
配置后,混合搜索将自动用于所有相似性搜索:
// This now uses hybrid search (vector + BM25 + RRF)
const results = await hybridVectorStore.similaritySearch(
  "how to prevent muscle soreness while running",
  5
);

完整的混合搜索示例

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);

用于检索增强生成的用法

有关如何将此向量存储用于检索增强生成 (RAG) 的指南,请参阅以下部分:

API 参考

有关所有 ElasticVectorSearch 功能和配置的详细文档,请参阅 API 参考.

相关资源