搶先一步
VMware 提供培訓和認證,以加速您的進步。
瞭解更多自 Spring Data Repositories 誕生以來,它就被設計為可擴充套件的,無論您是想自定義單個查詢方法,還是提供一個全新的基礎實現。
2024.1 版本增強了您擴充套件 repository 的能力,透過 自定義功能,讓任何人都可以輕鬆建立可在不同專案中共享的擴充套件。
讓我們透過一個例子來了解它在實踐中是如何運作的。
假設您使用 MongoDB 作為文件儲存來管理電影資料庫。 您希望透過您的 repository 介面利用 MongoDB Atlas 的 向量搜尋 功能來實現 AI 驅動的搜尋操作。 通常,您會建立像這樣的自定義 repository 片段
package io.movie.db;
interface AtlasMovieRepository {
List<Movie> vectorSearch(String index, String path, List<Double> vector, Limit limit);
}
在這裡,由於您正在使用 Movie
型別,因此您已經知道集合。 index 引數指定要使用的向量索引,path 定義儲存用於比較的 向量嵌入 的欄位。 相似度函式(例如,歐幾里得、餘弦或點積)在您設定索引時確定。 讓我們假設已經有一個餘弦向量索引。
在您的片段實現中,您需要建立 $vectorSearch
聚合階段,這是 MongoDB 執行向量搜尋的方法,並使用 MongoOperations
將其整合到 Aggregation API 中
package io.movie.db;
class AtlasMovieRepositoryFragment implements AtlasMovieRepository {
private final MongoOperations mongoOperations;
public AtlasMovieRepositoryFragment(MongoOperations mongoOperations) {
this.mongoOperations = mongoOperations;
}
@Override
public List<Movie> vectorSearch(String index, String path, List<Double> vector, Limit limit) {
Document $vectorSearch = createSearchDocument(index, path, vector, limit);
Aggregation aggregation = Aggregation.newAggregation(ctx -> $vectorSearch);
return mongoOperations.aggregate(aggregation, "movies", Movie.class).getMappedResults();
}
private static Document createSearchDocument(String index, String path, List<Double> vector, Limit limit) {
Document $vectorSearch = new Document();
$vectorSearch.append("index", index);
$vectorSearch.append("path", path);
$vectorSearch.append("queryVector", vector);
$vectorSearch.append("limit", limit.max());
return new Document("$vectorSearch", $vectorSearch);
}
}
現在,只需將片段整合到您的 MovieRepository
中
package io.movie.db;
interface MovieRepository extends CrudRepository<Movie, String>, AtlasMovieRepository { }
雖然這種方法有效,但您可能會注意到它與具有特定域型別 (Movie
) 的單個 repository 緊密耦合。 這使得它難以在其他專案中重用,因為片段實現與 repository 的包相關,並且是特定於域的。
但是向量搜尋並不侷限於我們的電影資料庫。 如果我們想在其他專案中重用此功能,而無需複製和修改解決方案該怎麼辦? 讓我們探索一種使其更通用的方法。
為了實現重用,我們將 AtlasMovieRepository
及其實現移動到一個單獨的專案中,以便可以共享它。 然後,我們在 META-INF/spring.factories
檔案中註冊該片段,以便 Spring Data 瞭解該擴充套件
api.mongodb.atlas.AtlasMovieRepository=api.mongodb.atlas.AtlasMovieRepositoryFragment
但是,當前的實現仍然與 Movie
型別相關聯,從而限制了其可重用性。 為了解決這個問題,我們需要使片段更加通用。 將 AtlasMovieRepository
重新命名為 AtlasRepository
並引入泛型型別引數。 不要忘記更新 spring.factories
檔案。
package api.mongodb.atlas;
interface AtlasRepository<T> {
List<T> vectorSearch(String index, String path, List<Double> vector, Limit limit);
}
接下來,我們更新實現以反映新的泛型方法,因為我們不能再假設我們正在定位 Movie
集合。 使用新引入的 RepositoryMethodContext
,我們可以訪問 repository 元資料並動態確定適當的集合名稱
package api.mongodb.atlas;
class AtlasRepositoryFragment<T> implements AtlasRepository<T>, RepositoryMetadataAccess {
private MongoOperations mongoOperations;
public AtlasRepositoryFragment(MongoOperations mongoOperations) {
this.mongoOperations = mongoOperations;
}
@Override
public List<T> vectorSearch(String index, String path, List<Double> vector, Limit limit) {
RepositoryMethodContext methodContext = RepositoryMethodContext.getContext();
Class<?> domainType = methodContext.getMetadata().getDomainType();
Document $vectorSearch = createSearchDocument(index, path, vector, limit);
Aggregation aggregation = Aggregation.newAggregation(ctx -> $vectorSearch);
return (List<T>) mongoOperations.aggregate(aggregation, mongoOperations.getCollectionName(domainType), domainType).getMappedResults();
}
private static Document createSearchDocument(String indexName, String path, List<Double> vector, Limit limit) {
Document $vectorSearch = new Document();
//…
}
}
提供的方法上下文不僅允許您訪問有關 repository 的一般資訊,還允許您訪問 repository 的泛型、方法等。在上面的程式碼片段中,我們假設 repository 域型別與我們的自定義片段對齊,這可能不是這種情況。 因此,相反,我們還可以透過 ResolvableType.forClass(getRepositoryInterface()).as(AtlasRepository.class).getGeneric(0)
讀取介面的元件型別,甚至檢查當前方法的返回型別以應用其他操作,例如投影等。 為了簡單起見,讓我們堅持這個示例中的域型別。
為避免不必要的開銷,我們僅為需要它的 repository 啟用上下文訪問。 仔細檢視上面的程式碼,您會發現 AtlasRepositoryFragment
類上有一個額外的 RepositoryMetadataAccess
介面。 此標記介面建議基礎結構在方法呼叫時提供所需的元資料。
透過該設定,您現在可以透過簡單地擴充套件您的 repository 在任何專案中使用自定義擴充套件
package io.movie.db;
interface MovieRepository extends CrudRepository<Movie, String>, AtlasRepository<Movie> { }
要試用它,請訪問 Spring Data Examples 專案,您將在其中找到準備執行的程式碼。