向量資料庫
向量資料庫是一種專門的資料庫型別,在 AI 應用程式中扮演著重要的角色。
在向量資料庫中,查詢與傳統關係型資料庫不同。它們執行的是相似性搜尋,而不是精確匹配。當給定一個向量作為查詢時,向量資料庫會返回與該查詢向量“相似”的向量。關於這種相似性如何在高層次上計算的更多細節,請參閱向量相似性。
向量資料庫用於將您的資料與 AI 模型整合。使用它們的第一步是將您的資料載入到向量資料庫中。然後,當用戶查詢需要傳送到 AI 模型時,首先會檢索一組相似的文件。這些文件隨後作為使用者問題的上下文,並與使用者查詢一起傳送到 AI 模型。這種技術被稱為檢索增強生成(RAG)。
以下部分描述了 Spring AI 介面,用於使用多種向量資料庫實現以及一些高層次的示例用法。
最後一部分旨在揭開向量資料庫中相似性搜尋底層方法的神秘面紗。
API 概述
本節將作為 Spring AI 框架中 VectorStore 介面及其相關類的指南。
Spring AI 提供了一個抽象的 API,用於透過 VectorStore 介面及其只讀對應物 VectorStoreRetriever 介面與向量資料庫進行互動。
VectorStoreRetriever 介面
Spring AI 提供了一個只讀介面,名為 VectorStoreRetriever,它僅暴露文件檢索功能。
@FunctionalInterface
public interface VectorStoreRetriever {
List<Document> similaritySearch(SearchRequest request);
default List<Document> similaritySearch(String query) {
return this.similaritySearch(SearchRequest.builder().query(query).build());
}
}
此函式式介面設計用於您只需從向量儲存中檢索文件而無需執行任何修改操作的用例。它遵循最小許可權原則,僅暴露文件檢索所需的必要功能。
VectorStore 介面
VectorStore 介面擴充套件了 VectorStoreRetriever 並增加了修改功能。
public interface VectorStore extends DocumentWriter, VectorStoreRetriever {
default String getName() {
return this.getClass().getSimpleName();
}
void add(List<Document> documents);
void delete(List<String> idList);
void delete(Filter.Expression filterExpression);
default void delete(String filterExpression) { ... }
default <T> Optional<T> getNativeClient() {
return Optional.empty();
}
}
VectorStore 介面結合了讀寫操作,允許您在向量資料庫中新增、刪除和搜尋文件。
SearchRequest 構建器
public class SearchRequest {
public static final double SIMILARITY_THRESHOLD_ACCEPT_ALL = 0.0;
public static final int DEFAULT_TOP_K = 4;
private String query = "";
private int topK = DEFAULT_TOP_K;
private double similarityThreshold = SIMILARITY_THRESHOLD_ACCEPT_ALL;
@Nullable
private Filter.Expression filterExpression;
public static Builder from(SearchRequest originalSearchRequest) {
return builder().query(originalSearchRequest.getQuery())
.topK(originalSearchRequest.getTopK())
.similarityThreshold(originalSearchRequest.getSimilarityThreshold())
.filterExpression(originalSearchRequest.getFilterExpression());
}
public static class Builder {
private final SearchRequest searchRequest = new SearchRequest();
public Builder query(String query) {
Assert.notNull(query, "Query can not be null.");
this.searchRequest.query = query;
return this;
}
public Builder topK(int topK) {
Assert.isTrue(topK >= 0, "TopK should be positive.");
this.searchRequest.topK = topK;
return this;
}
public Builder similarityThreshold(double threshold) {
Assert.isTrue(threshold >= 0 && threshold <= 1, "Similarity threshold must be in [0,1] range.");
this.searchRequest.similarityThreshold = threshold;
return this;
}
public Builder similarityThresholdAll() {
this.searchRequest.similarityThreshold = 0.0;
return this;
}
public Builder filterExpression(@Nullable Filter.Expression expression) {
this.searchRequest.filterExpression = expression;
return this;
}
public Builder filterExpression(@Nullable String textExpression) {
this.searchRequest.filterExpression = (textExpression != null)
? new FilterExpressionTextParser().parse(textExpression) : null;
return this;
}
public SearchRequest build() {
return this.searchRequest;
}
}
public String getQuery() {...}
public int getTopK() {...}
public double getSimilarityThreshold() {...}
public Filter.Expression getFilterExpression() {...}
}
要將資料插入向量資料庫,請將其封裝在 Document 物件中。 Document 類封裝了來自資料來源(如 PDF 或 Word 文件)的內容,幷包含表示為字串的文字。它還包含鍵值對形式的元資料,包括檔名等詳細資訊。
插入向量資料庫後,文字內容會使用嵌入模型轉換為數字陣列(即 float[]),稱為向量嵌入。嵌入模型,例如 Word2Vec、GLoVE 和 BERT,或 OpenAI 的 text-embedding-ada-002,用於將單詞、句子或段落轉換為這些向量嵌入。
向量資料庫的作用是儲存這些嵌入並促進相似性搜尋。它本身不生成嵌入。要建立向量嵌入,應使用 EmbeddingModel。
介面中的 similaritySearch 方法允許檢索與給定查詢字串相似的文件。這些方法可以透過使用以下引數進行微調:
-
k:一個整數,指定要返回的相似文件的最大數量。這通常被稱為“top K”搜尋或“K 最近鄰”(KNN)。 -
threshold:一個介於 0 到 1 之間的雙精度值,值越接近 1 表示相似度越高。預設情況下,例如,如果您將閾值設定為 0.75,則只返回相似度高於此值的文件。 -
Filter.Expression:一個用於傳遞流式 DSL(領域特定語言)表示式的類,其功能類似於 SQL 中的“where”子句,但它專門應用於Document的元資料鍵值對。 -
filterExpression:基於 ANTLR4 的外部 DSL,接受字串形式的過濾表示式。例如,對於國家、年份和isActive等元資料鍵,您可以使用如下表達式:country == 'UK' && year >= 2020 && isActive == true.
有關 Filter.Expression 的更多資訊,請參閱元資料過濾器一節。
模式初始化
某些向量儲存在使用前需要初始化其後端模式。預設情況下不會為您初始化。您必須透過為適當的建構函式引數傳遞 boolean 值或(如果使用 Spring Boot)在 application.properties 或 application.yml 中將適當的 initialize-schema 屬性設定為 true 來選擇啟用。請檢視您正在使用的向量儲存的文件以獲取具體的屬性名稱。
批處理策略
在使用向量儲存時,通常需要嵌入大量文件。雖然一次性呼叫嵌入所有文件看起來很簡單,但這種方法可能會導致問題。嵌入模型將文字作為標記進行處理,並且具有最大標記限制,通常稱為上下文視窗大小。此限制限制了單個嵌入請求中可以處理的文字量。嘗試在一次呼叫中嵌入太多標記可能會導致錯誤或截斷的嵌入。
為了解決此標記限制,Spring AI 實現了批處理策略。這種方法將大型文件集分解為適合嵌入模型最大上下文視窗的較小批次。批處理不僅解決了標記限制問題,還可以提高效能並更有效地利用 API 速率限制。
Spring AI 透過 BatchingStrategy 介面提供此功能,該介面允許根據文件的標記計數以子批次處理文件。
核心 BatchingStrategy 介面定義如下:
public interface BatchingStrategy {
List<List<Document>> batch(List<Document> documents);
}
此介面定義了一個方法 batch,它接受一個文件列表並返回一個文件批次列表。
預設實現
Spring AI 提供了一個名為 TokenCountBatchingStrategy 的預設實現。此策略根據文件的令牌計數對文件進行批處理,確保每個批次不超過計算出的最大輸入令牌計數。
TokenCountBatchingStrategy 的主要特點:
-
使用OpenAI 的最大輸入令牌計數(8191)作為預設上限。
-
包含一個保留百分比(預設 10%),為潛在的開銷提供緩衝。
-
計算實際最大輸入令牌計數為:
actualMaxInputTokenCount = originalMaxInputTokenCount * (1 - RESERVE_PERCENTAGE)
該策略估計每個文件的令牌計數,將它們分組到不超過最大輸入令牌計數的批次中,如果單個文件超過此限制,則會丟擲異常。
您還可以自定義 TokenCountBatchingStrategy 以更好地滿足您的特定需求。這可以透過在 Spring Boot @Configuration 類中建立具有自定義引數的新例項來完成。
以下是如何建立自定義 TokenCountBatchingStrategy bean 的示例:
@Configuration
public class EmbeddingConfig {
@Bean
public BatchingStrategy customTokenCountBatchingStrategy() {
return new TokenCountBatchingStrategy(
EncodingType.CL100K_BASE, // Specify the encoding type
8000, // Set the maximum input token count
0.1 // Set the reserve percentage
);
}
}
在此配置中:
-
EncodingType.CL100K_BASE:指定用於分詞的編碼型別。此編碼型別由JTokkitTokenCountEstimator用於準確估計令牌計數。 -
8000:設定最大輸入令牌計數。此值應小於或等於嵌入模型的最大上下文視窗大小。 -
0.1:設定保留百分比。從最大輸入令牌計數中保留的令牌百分比。這為處理過程中潛在的令牌計數增加建立了一個緩衝區。
預設情況下,此建構函式使用 Document.DEFAULT_CONTENT_FORMATTER 進行內容格式化,並使用 MetadataMode.NONE 進行元資料處理。如果您需要自定義這些引數,可以使用帶有附加引數的完整建構函式。
一旦定義,此自定義 TokenCountBatchingStrategy bean 將由您的應用程式中的 EmbeddingModel 實現自動使用,取代預設策略。
TokenCountBatchingStrategy 內部使用 TokenCountEstimator(特別是 JTokkitTokenCountEstimator)來計算令牌計數以進行高效批處理。這確保了根據指定的編碼型別進行準確的令牌估計。
此外,TokenCountBatchingStrategy 透過允許您傳入自己的 TokenCountEstimator 介面實現來提供靈活性。此功能使您能夠使用根據您的特定需求定製的自定義令牌計數策略。例如:
TokenCountEstimator customEstimator = new YourCustomTokenCountEstimator();
TokenCountBatchingStrategy strategy = new TokenCountBatchingStrategy(
this.customEstimator,
8000, // maxInputTokenCount
0.1, // reservePercentage
Document.DEFAULT_CONTENT_FORMATTER,
MetadataMode.NONE
);
使用自動截斷
某些嵌入模型(如 Vertex AI 文字嵌入)支援 auto_truncate 功能。啟用此功能後,模型會悄無聲息地截斷超出最大大小的文字輸入並繼續處理;停用時,它會為過大的輸入丟擲明確的錯誤。
當使用批處理策略進行自動截斷時,您必須將批處理策略配置為比模型實際最大值高得多的輸入令牌計數。這可以防止批處理策略因大文件而引發異常,從而允許嵌入模型在內部處理截斷。
自動截斷配置
啟用自動截斷時,將批處理策略的最大輸入令牌計數設定得遠高於模型的實際限制。這可以防止批處理策略因大文件而引發異常,從而允許嵌入模型在內部處理截斷。
以下是使用 Vertex AI 自動截斷和自定義 BatchingStrategy,然後將其用於 PgVectorStore 的示例配置:
@Configuration
public class AutoTruncationEmbeddingConfig {
@Bean
public VertexAiTextEmbeddingModel vertexAiEmbeddingModel(
VertexAiEmbeddingConnectionDetails connectionDetails) {
VertexAiTextEmbeddingOptions options = VertexAiTextEmbeddingOptions.builder()
.model(VertexAiTextEmbeddingOptions.DEFAULT_MODEL_NAME)
.autoTruncate(true) // Enable auto-truncation
.build();
return new VertexAiTextEmbeddingModel(connectionDetails, options);
}
@Bean
public BatchingStrategy batchingStrategy() {
// Only use a high token limit if auto-truncation is enabled in your embedding model.
// Set a much higher token count than the model actually supports
// (e.g., 132,900 when Vertex AI supports only up to 20,000)
return new TokenCountBatchingStrategy(
EncodingType.CL100K_BASE,
132900, // Artificially high limit
0.1 // 10% reserve
);
}
@Bean
public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel, BatchingStrategy batchingStrategy) {
return PgVectorStore.builder(jdbcTemplate, embeddingModel)
// other properties omitted here
.build();
}
}
在此配置中:
-
嵌入模型已啟用自動截斷功能,使其能夠優雅地處理過大的輸入。
-
批處理策略使用了一個人為設定的高令牌限制(132,900),遠大於實際模型限制(20,000)。
-
向量儲存使用配置好的嵌入模型和自定義的
BatchingStrategybean。
工作原理
這種方法有效的原因是:
-
TokenCountBatchingStrategy檢查任何單個文件是否超過配置的最大值,如果超過則丟擲IllegalArgumentException。 -
透過在批處理策略中設定一個非常高的限制,我們確保此檢查永遠不會失敗。
-
超出模型限制的文件或批次會透過嵌入模型的自動截斷功能進行靜默截斷和處理。
最佳實踐
使用自動截斷時:
-
將批處理策略的最大輸入令牌計數設定為至少比模型實際限制大 5-10 倍,以避免批處理策略過早丟擲異常。
-
監控日誌中嵌入模型的截斷警告(注意:並非所有模型都記錄截斷事件)。
-
考慮靜默截斷對嵌入質量的影響。
-
使用示例文件進行測試,以確保截斷的嵌入仍然符合您的要求。
-
為將來的維護者記錄此配置,因為它是非標準的。
| 雖然自動截斷可以防止錯誤,但它可能導致不完整的嵌入。長文件末尾的重要資訊可能會丟失。如果您的應用程式要求嵌入所有內容,請在嵌入之前將文件分成更小的塊。 |
Spring Boot 自動配置
如果您正在使用 Spring Boot 自動配置,您必須提供一個自定義的 BatchingStrategy bean 來覆蓋 Spring AI 附帶的預設 bean
@Bean
public BatchingStrategy customBatchingStrategy() {
// This bean will override the default BatchingStrategy
return new TokenCountBatchingStrategy(
EncodingType.CL100K_BASE,
132900, // Much higher than model's actual limit
0.1
);
}
您的應用程式上下文中存在此 bean 將自動替換所有向量儲存使用的預設批處理策略。
自定義實現
雖然 TokenCountBatchingStrategy 提供了一個健壯的預設實現,但您可以自定義批處理策略以滿足您的特定需求。這可以透過 Spring Boot 的自動配置來完成。
要自定義批處理策略,請在您的 Spring Boot 應用程式中定義一個 BatchingStrategy bean
@Configuration
public class EmbeddingConfig {
@Bean
public BatchingStrategy customBatchingStrategy() {
return new CustomBatchingStrategy();
}
}
然後,此自定義 BatchingStrategy 將由您的應用程式中的 EmbeddingModel 實現自動使用。
Spring AI 支援的向量儲存配置為使用預設的 TokenCountBatchingStrategy。SAP Hana 向量儲存目前未配置為批處理。 |
向量儲存實現
以下是 VectorStore 介面的可用實現:
-
Azure 向量搜尋 - Azure 向量儲存。
-
Apache Cassandra - Apache Cassandra 向量儲存。
-
Chroma 向量儲存 - Chroma 向量儲存。
-
Elasticsearch 向量儲存 - Elasticsearch 向量儲存。
-
GemFire 向量儲存 - GemFire 向量儲存。
-
MariaDB 向量儲存 - MariaDB 向量儲存。
-
Milvus 向量儲存 - Milvus 向量儲存。
-
MongoDB Atlas 向量儲存 - MongoDB Atlas 向量儲存。
-
Neo4j 向量儲存 - Neo4j 向量儲存。
-
OpenSearch 向量儲存 - OpenSearch 向量儲存。
-
Oracle 向量儲存 - Oracle 資料庫 向量儲存。
-
PgVector 儲存 - PostgreSQL/PGVector 向量儲存。
-
Pinecone 向量儲存 - Pinecone 向量儲存。
-
Qdrant 向量儲存 - Qdrant 向量儲存。
-
Redis 向量儲存 - Redis 向量儲存。
-
SAP Hana 向量儲存 - SAP HANA 向量儲存。
-
Typesense 向量儲存 - Typesense 向量儲存。
-
Weaviate 向量儲存 - Weaviate 向量儲存。
-
SimpleVectorStore - 一個簡單的持久化向量儲存實現,適合教育目的。
未來版本可能會支援更多實現。
如果您有一個需要 Spring AI 支援的向量資料庫,請在 GitHub 上提出問題,或者更好地,提交一個包含實現的拉取請求。
有關每個 VectorStore 實現的資訊可以在本章的子部分中找到。
示例用法
要為向量資料庫計算嵌入,您需要選擇一個與所使用的高階 AI 模型匹配的嵌入模型。
例如,對於 OpenAI 的 ChatGPT,我們使用 OpenAiEmbeddingModel 和名為 text-embedding-ada-002 的模型。
Spring Boot 啟動器為 OpenAI 提供的自動配置使得 EmbeddingModel 的實現可以在 Spring 應用程式上下文中進行依賴注入。
寫入向量儲存
將資料載入到向量儲存中的一般用法類似於批處理作業,首先將資料載入到 Spring AI 的 Document 類中,然後呼叫 VectorStore 介面上的 add 方法。
給定一個表示 JSON 檔案的原始檔的 String 引用,其中包含我們希望載入到向量資料庫中的資料,我們使用 Spring AI 的 JsonReader 來載入 JSON 中的特定欄位,它將這些欄位分解成小塊,然後將這些小塊傳遞給向量儲存實現。 VectorStore 實現計算嵌入並將 JSON 和嵌入儲存在向量資料庫中。
@Autowired
VectorStore vectorStore;
void load(String sourceFile) {
JsonReader jsonReader = new JsonReader(new FileSystemResource(sourceFile),
"price", "name", "shortDescription", "description", "tags");
List<Document> documents = jsonReader.get();
this.vectorStore.add(documents);
}
從向量儲存中讀取
稍後,當用戶問題傳遞到 AI 模型時,會進行相似性搜尋以檢索相似文件,然後將這些文件“填充”到提示中,作為使用者問題的上下文。
對於只讀操作,您可以使用 VectorStore 介面或更集中的 VectorStoreRetriever 介面。
@Autowired
VectorStoreRetriever retriever; // Could also use VectorStore here
String question = "<question from user>";
List<Document> similarDocuments = retriever.similaritySearch(question);
// Or with more specific search parameters
SearchRequest request = SearchRequest.builder()
.query(question)
.topK(5) // Return top 5 results
.similarityThreshold(0.7) // Only return results with similarity score >= 0.7
.build();
List<Document> filteredDocuments = retriever.similaritySearch(request);
其他選項可以傳遞到 similaritySearch 方法中,以定義要檢索的文件數量和相似性搜尋的閾值。
讀寫操作分離
使用單獨的介面可以清晰地定義哪些元件需要寫入許可權,哪些元件只需要讀取許可權。
// Write operations in a service that needs full access
@Service
class DocumentIndexer {
private final VectorStore vectorStore;
DocumentIndexer(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
public void indexDocuments(List<Document> documents) {
vectorStore.add(documents);
}
}
// Read-only operations in a service that only needs retrieval
@Service
class DocumentRetriever {
private final VectorStoreRetriever retriever;
DocumentRetriever(VectorStoreRetriever retriever) {
this.retriever = retriever;
}
public List<Document> findSimilar(String query) {
return retriever.similaritySearch(query);
}
}
這種關注點分離有助於建立更易於維護和更安全的應用程式,透過將對修改操作的訪問限制在真正需要它們的元件。
使用 VectorStoreRetriever 進行檢索操作
VectorStoreRetriever 介面提供了向量儲存的只讀檢視,僅公開相似性搜尋功能。這遵循最小許可權原則,在 RAG(檢索增強生成)應用程式中特別有用,在這些應用程式中,您只需要檢索文件而無需修改底層資料。
使用 VectorStoreRetriever 的好處
-
關注點分離:清晰地分離讀操作和寫操作。
-
介面隔離:只需要檢索功能的客戶端不會暴露於修改方法。
-
函式式介面:對於簡單的用例,可以透過 Lambda 表示式或方法引用實現。
-
減少依賴:只需要執行搜尋的元件不需要依賴完整的
VectorStore介面。
示例用法
當您只需要執行相似性搜尋時,可以直接使用 VectorStoreRetriever。
@Service
public class DocumentRetrievalService {
private final VectorStoreRetriever retriever;
public DocumentRetrievalService(VectorStoreRetriever retriever) {
this.retriever = retriever;
}
public List<Document> findSimilarDocuments(String query) {
return retriever.similaritySearch(query);
}
public List<Document> findSimilarDocumentsWithFilters(String query, String country) {
SearchRequest request = SearchRequest.builder()
.query(query)
.topK(5)
.filterExpression("country == '" + country + "'")
.build();
return retriever.similaritySearch(request);
}
}
在此示例中,該服務僅依賴於 VectorStoreRetriever 介面,明確表明它只執行檢索操作,而不修改向量儲存。
與 RAG 應用程式整合
VectorStoreRetriever 介面在 RAG 應用程式中特別有用,您需要在其中檢索相關文件以為 AI 模型提供上下文。
@Service
public class RagService {
private final VectorStoreRetriever retriever;
private final ChatModel chatModel;
public RagService(VectorStoreRetriever retriever, ChatModel chatModel) {
this.retriever = retriever;
this.chatModel = chatModel;
}
public String generateResponse(String userQuery) {
// Retrieve relevant documents
List<Document> relevantDocs = retriever.similaritySearch(userQuery);
// Extract content from documents to use as context
String context = relevantDocs.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n\n"));
// Generate response using the retrieved context
String prompt = "Context information:\n" + context + "\n\nUser query: " + userQuery;
return chatModel.generate(prompt);
}
}
此模式允許在 RAG 應用程式中檢索元件和生成元件之間實現清晰的分離。
元資料過濾器
本節描述了可用於查詢結果的各種過濾器。
篩選字串
您可以將類似 SQL 的過濾表示式作為 String 傳遞給 similaritySearch 的一個過載。
考慮以下示例:
-
"country == 'BG'" -
"genre == 'drama' && year >= 2020" -
"genre in ['comedy', 'documentary', 'drama']"
Filter.Expression
您可以使用 FilterExpressionBuilder 建立 Filter.Expression 例項,該構建器公開了流式 API。一個簡單的示例如下:
FilterExpressionBuilder b = new FilterExpressionBuilder();
Expression expression = this.b.eq("country", "BG").build();
您可以使用以下運算子構建複雜的表示式:
EQUALS: '=='
MINUS : '-'
PLUS: '+'
GT: '>'
GE: '>='
LT: '<'
LE: '<='
NE: '!='
您可以使用以下運算子組合表示式:
AND: 'AND' | 'and' | '&&';
OR: 'OR' | 'or' | '||';
考慮以下示例:
Expression exp = b.and(b.eq("genre", "drama"), b.gte("year", 2020)).build();
您還可以使用以下運算子:
IN: 'IN' | 'in';
NIN: 'NIN' | 'nin';
NOT: 'NOT' | 'not';
考慮以下示例
Expression exp = b.and(b.in("genre", "drama", "documentary"), b.not(b.lt("year", 2020))).build();
從向量儲存中刪除文件
向量儲存介面提供了多種刪除文件的方法,允許您透過特定的文件 ID 或使用過濾表示式來刪除資料。
按文件 ID 刪除
刪除文件最簡單的方法是提供文件 ID 列表。
void delete(List<String> idList);
此方法將刪除所有 ID 與所提供列表中匹配的文件。如果列表中任何 ID 在儲存中不存在,則會被忽略。
// Create and add document
Document document = new Document("The World is Big",
Map.of("country", "Netherlands"));
vectorStore.add(List.of(document));
// Delete document by ID
vectorStore.delete(List.of(document.getId()));
按過濾表示式刪除
對於更復雜的刪除條件,您可以使用過濾表示式:
void delete(Filter.Expression filterExpression);
此方法接受一個 Filter.Expression 物件,該物件定義了應刪除文件的條件。當您需要根據文件的元資料屬性刪除文件時,它特別有用。
// Create test documents with different metadata
Document bgDocument = new Document("The World is Big",
Map.of("country", "Bulgaria"));
Document nlDocument = new Document("The World is Big",
Map.of("country", "Netherlands"));
// Add documents to the store
vectorStore.add(List.of(bgDocument, nlDocument));
// Delete documents from Bulgaria using filter expression
Filter.Expression filterExpression = new Filter.Expression(
Filter.ExpressionType.EQ,
new Filter.Key("country"),
new Filter.Value("Bulgaria")
);
vectorStore.delete(filterExpression);
// Verify deletion with search
SearchRequest request = SearchRequest.builder()
.query("World")
.filterExpression("country == 'Bulgaria'")
.build();
List<Document> results = vectorStore.similaritySearch(request);
// results will be empty as Bulgarian document was deleted
按字串過濾表示式刪除
為了方便起見,您還可以使用基於字串的過濾表示式刪除文件。
void delete(String filterExpression);
此方法將提供的字串過濾器內部轉換為 Filter.Expression 物件。當您的過濾器條件採用字串格式時很有用。
// Create and add documents
Document bgDocument = new Document("The World is Big",
Map.of("country", "Bulgaria"));
Document nlDocument = new Document("The World is Big",
Map.of("country", "Netherlands"));
vectorStore.add(List.of(bgDocument, nlDocument));
// Delete Bulgarian documents using string filter
vectorStore.delete("country == 'Bulgaria'");
// Verify remaining documents
SearchRequest request = SearchRequest.builder()
.query("World")
.topK(5)
.build();
List<Document> results = vectorStore.similaritySearch(request);
// results will only contain the Netherlands document
呼叫刪除 API 時的錯誤處理
所有刪除方法都可能在出錯時丟擲異常。
最佳實踐是將刪除操作包裝在 try-catch 塊中。
try {
vectorStore.delete("country == 'Bulgaria'");
}
catch (Exception e) {
logger.error("Invalid filter expression", e);
}
文件版本控制用例
一個常見的場景是管理文件版本,您需要上傳新版本的文件,同時刪除舊版本。以下是如何使用過濾表示式處理此問題:
// Create initial document (v1) with version metadata
Document documentV1 = new Document(
"AI and Machine Learning Best Practices",
Map.of(
"docId", "AIML-001",
"version", "1.0",
"lastUpdated", "2024-01-01"
)
);
// Add v1 to the vector store
vectorStore.add(List.of(documentV1));
// Create updated version (v2) of the same document
Document documentV2 = new Document(
"AI and Machine Learning Best Practices - Updated",
Map.of(
"docId", "AIML-001",
"version", "2.0",
"lastUpdated", "2024-02-01"
)
);
// First, delete the old version using filter expression
Filter.Expression deleteOldVersion = new Filter.Expression(
Filter.ExpressionType.AND,
Arrays.asList(
new Filter.Expression(
Filter.ExpressionType.EQ,
new Filter.Key("docId"),
new Filter.Value("AIML-001")
),
new Filter.Expression(
Filter.ExpressionType.EQ,
new Filter.Key("version"),
new Filter.Value("1.0")
)
)
);
vectorStore.delete(deleteOldVersion);
// Add the new version
vectorStore.add(List.of(documentV2));
// Verify only v2 exists
SearchRequest request = SearchRequest.builder()
.query("AI and Machine Learning")
.filterExpression("docId == 'AIML-001'")
.build();
List<Document> results = vectorStore.similaritySearch(request);
// results will contain only v2 of the document
您也可以使用字串過濾表示式完成相同的操作:
// Delete old version using string filter
vectorStore.delete("docId == 'AIML-001' AND version == '1.0'");
// Add new version
vectorStore.add(List.of(documentV2));