MongoDB Atlas
MongoDB Atlas 是一项全托管云数据库服务,可在 AWS、Azure 和 GCP 上使用。它支持在 MongoDB 文档数据上原生使用 向量搜索(Vector Search)以及全文搜索(BM25 算法)。
Atlas Vector Search
功能允许你将嵌入向量存储在 MongoDB 文档中、创建向量搜索索引,
并使用一种称为 Hierarchical Navigable Small Worlds(分层可导航小世界)的近似最近邻算法
执行 KNN 搜索。
LangChain4j 与 MongoDB 的集成在内部通过
$vectorSearch
聚合阶段实现 Atlas Vector Search。
你可以将 Atlas Vector Search 与 LangChain4j 结合使用,对数据进行语义搜索, 并构建简单的 RAG 实现。若要查看完成这些任务的完整教程,请参阅 MongoDB Atlas 文档中的 Get Started with the LangChain4j Integration 教程。
先决条件
要使用 Atlas Vector Search,部署必须运行以下 MongoDB Server 版本之一:
- 6.0.11 或更高版本
- 7.0.2 或更高版本
MongoDB 提供永久免费的集群。请参阅 Get Started with Atlas 教程, 了解如何创建账户并连接到部署。
你还必须拥有带额度的 API 密钥,用于提供嵌入模型的 LLM 服务,例如 Voyage AI(提供免费层级)。对于 RAG 应用,你还必须拥有支持聊天模型功能的服务的 API 密钥,例如 OpenAI 或来自 HuggingFace 的模型。
环境与安装
- 在你喜欢的 IDE 中创建新的 Java 应用程序。
- 向应用程序添加以下依赖项,以安装 LangChain4j 和 MongoDB Java Sync Driver:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-mongodb-atlas</artifactId>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>5.4.0</version>
</dependency>
你还必须安装嵌入模型的依赖项,例如 Voyage AI:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-voyage-ai</artifactId>
</dependency>
我们还建议添加 LangChain4j BOM:
<dependencyManagement>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-bom</artifactId>
<version>1.18.1-beta28</version>
<type>pom</type>
</dependency>
</dependencyManagement>
将 MongoDB Atlas 用作嵌入存储
- 实例化一个嵌入模型。
- 将 MongoDB Atlas 实例化为嵌入存储。
构建 MongoDbEmbeddingStore 实例时,可以通过向 createIndex() 方法传入 true
来启用自动索引创建。
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import dev.langchain4j.data.document.Metadata;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.voyageai.VoyageAiEmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import dev.langchain4j.store.embedding.EmbeddingSearchResult;
import dev.langchain4j.store.embedding.filter.comparison.*;
import dev.langchain4j.store.embedding.mongodb.IndexMapping;
import dev.langchain4j.store.embedding.mongodb.MongoDbEmbeddingStore;
import org.bson.Document;
import java.io.*;
import java.util.*;
String embeddingApiKey = System.getenv("VOYAGE_AI_KEY");
String uri = System.getenv("MONGODB_URI");
EmbeddingModel embeddingModel = VoyageAiEmbeddingModel.builder()
.apiKey(embeddingApiKey)
.modelName("voyage-3")
.build();
MongoClient mongoClient = MongoClients.create(uri);
System.out.println("Instantiating the embedding store...");
// Set to false if the vector index already exists
Boolean createIndex = true;
IndexMapping indexMapping = IndexMapping.builder()
.dimension(embeddingModel.dimension())
.metadataFieldNames(new HashSet<>())
.build();
MongoDbEmbeddingStore embeddingStore = MongoDbEmbeddingStore.builder()
.databaseName("search")
.collectionName("langchaintest")
.createIndex(createIndex)
.indexName("vector_index")
.indexMapping(indexMapping)
.fromClient(mongoClient)
.build();
将数据存储到 MongoDB
以下代码演示如何将文档持久化到嵌入存储。
embed() 方法会为文档中 text 字段的值生成嵌入向量。
ArrayList<Document> docs = new ArrayList<>();
docs.add(new Document()
.append("text", "Penguins are flightless seabirds that live almost exclusively below the equator. Some island-dwellers can be found in warmer climates.")
.append("metadata", new Metadata(Map.of("website", "Science Direct"))));
docs.add(new Document()
.append("text", "Emperor penguins are amazing birds. They not only survive the Antarctic winter, but they breed during the worst weather conditions on earth.")
.append("metadata", new Metadata(Map.of("website", "Our Earth"))));
docs.add(...);
System.out.println("Persisting document embeddings...");
for (Document doc : docs) {
TextSegment segment = TextSegment.from(
doc.getString("text"),
doc.get("metadata", Metadata.class)
);
Embedding embedding = embeddingModel.embed(segment).content();
embeddingStore.add(embedding, segment);
}
执行语义 / 相似度搜索
以下代码演示如何创建搜索请求:将查询转换为向量,
并返回语义上相似的文档。得到的 EmbeddingMatch 实例
包含文档内容,以及描述每个结果与查询匹配程度的分数。
String query = "Where do penguins live?";
Embedding queryEmbedding = embeddingModel.embed(query).content();
EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(3)
.build();
System.out.println("Performing the query...");
EmbeddingSearchResult<TextSegment> searchResult = embeddingStore.search(searchRequest);
List<EmbeddingMatch<TextSegment>> matches = searchResult.matches();
for (EmbeddingMatch<TextSegment> embeddingMatch : matches) {
System.out.println("Response: " + embeddingMatch.embedded().text());
System.out.println("Author: " + embeddingMatch.embedded().metadata().getString("author"));
System.out.println("Score: " + embeddingMatch.score());
}
元数据过滤
你可以在构建 EmbeddingSearchRequest 时使用 filter() 方法实现元数据过滤。
filter() 方法接受一个继承自
Filter
的参数。
以下代码实现了元数据过滤 ,仅保留 website 的值属于所列值之一的文档。
EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.filter(new IsIn("website", List.of("Our Earth", "Natural Habitats")))
.maxResults(3)
.build();
RAG
若要查看以 MongoDB Atlas 作为向量存储实现 RAG 的说明,请参阅 Atlas 文档中 LangChain4j 教程的 Use Your Data to Answer Questions 部分。