> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-HK/llms.txt # 在向量資料庫儲存嵌入向量 產生嵌入向量後,你需要將它們儲存在支援向量相似度搜尋的資料庫中。Mastra 提供一致的介面,讓你可在不同向量資料庫中儲存及查詢嵌入向量。 ## 支援的資料庫 **MongoDB**: ```ts import { MongoDBVector } from '@mastra/mongodb' const store = new MongoDBVector({ id: 'mongodb-vector', uri: process.env.MONGODB_URI, dbName: process.env.MONGODB_DB_NAME, }) await store.createIndex({ indexName: 'myCollection', dimension: 1536, }) await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` ### 使用 MongoDB Atlas Vector Search 如需詳細設定指引及最佳做法,請參閱 [MongoDB Atlas Vector Search 官方文件](https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-overview/?utm_campaign=devrel\&utm_source=third-party-content\&utm_medium=cta\&utm_content=mastra-docs)。 ### 配合 MongoDB 使用 VoyageAI MongoDB 可與針對檢索工作最佳化的 VoyageAI 嵌入模型無縫配合。如需完整範例及專用模型,請參閱 [VoyageAI 嵌入向量文件](https://mastra.zisheng.pro/zh-HK/models/embeddings)及 [MongoDB 向量參考](https://mastra.zisheng.pro/zh-HK/reference/vectors/mongodb)。 ### 混合搜尋(向量 + 全文) MongoDB 支援混合搜尋,透過伺服器端的 `$rankFusion` 融合向量相似度與 BM25 全文搜尋(需要 MongoDB >= 8.0;由 8.1 起正式提供,並已在 Atlas 8.0.x 啟用)。當你想結合語義及關鍵字檢索時,這項功能非常實用: ```ts await store.createSearchIndex({ indexName: 'myCollection', fields: ['text'] }) const results = await store.hybridQuery({ indexName: 'myCollection', queryVector: embedding, query: 'search terms', paths: ['text'], topK: 10, }) ``` 有關 `createSearchIndex()`、`textQuery()` 及 `hybridQuery()` 的詳情,請參閱 [MongoDB 向量參考](https://mastra.zisheng.pro/zh-HK/reference/vectors/mongodb)。 **PgVector**: ```ts import { PgVector } from '@mastra/pg' const store = new PgVector({ id: 'pg-vector', connectionString: process.env.POSTGRES_CONNECTION_STRING, }) await store.createIndex({ indexName: 'myCollection', dimension: 1536, }) await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` ### 配合 pgvector 使用 PostgreSQL 對於已使用 PostgreSQL 並希望盡量降低基礎設施複雜度的團隊,安裝 pgvector 擴充套件的 PostgreSQL 是一個合適方案。 如需詳細設定指引及最佳做法,請參閱 [pgvector 官方程式碼庫](https://github.com/pgvector/pgvector)。 **OracleDB**: ```ts import { OracleVector } from '@mastra/oracledb' const store = new OracleVector({ id: 'oracle-vector', user: process.env.ORACLE_DATABASE_USER, password: process.env.ORACLE_DATABASE_PASSWORD, connectString: process.env.ORACLE_DATABASE_CONNECT_STRING, }) await store.createIndex({ indexName: 'myCollection', dimension: 1536, indexConfig: { type: 'none' }, }) await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` ### 使用 Oracle Database Vector Search OracleDB 將嵌入向量儲存在原生 `VECTOR` 欄中,並以 Oracle JSON 儲存元資料。預設使用精確搜尋;你可設定 HNSW 及 IVF 索引,以配合經調校的部署。 **Pinecone**: ```ts import { PineconeVector } from '@mastra/pinecone' const store = new PineconeVector({ id: 'pinecone-vector', apiKey: process.env.PINECONE_API_KEY, }) await store.createIndex({ indexName: 'myCollection', dimension: 1536, }) await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` **Qdrant**: ```ts import { QdrantVector } from '@mastra/qdrant' const store = new QdrantVector({ id: 'qdrant-vector', url: process.env.QDRANT_URL, apiKey: process.env.QDRANT_API_KEY, }) await store.createIndex({ indexName: 'myCollection', dimension: 1536, }) await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` **Chroma**: ```ts import { ChromaVector } from '@mastra/chroma' // Running Chroma locally // const store = new ChromaVector() // Running on Chroma Cloud const store = new ChromaVector({ id: 'chroma-vector', apiKey: process.env.CHROMA_API_KEY, tenant: process.env.CHROMA_TENANT, database: process.env.CHROMA_DATABASE, }) await store.createIndex({ indexName: 'myCollection', dimension: 1536, }) await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` **Astra**: ```ts import { AstraVector } from '@mastra/astra' const store = new AstraVector({ id: 'astra-vector', token: process.env.ASTRA_DB_TOKEN, endpoint: process.env.ASTRA_DB_ENDPOINT, keyspace: process.env.ASTRA_DB_KEYSPACE, }) await store.createIndex({ indexName: 'myCollection', dimension: 1536, }) await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` **libSQL**: ```ts import { LibSQLVector } from '@mastra/core/vector/libsql' const store = new LibSQLVector({ id: 'libsql-vector', url: process.env.DATABASE_URL, authToken: process.env.DATABASE_AUTH_TOKEN, // Optional: for Turso cloud databases }) await store.createIndex({ indexName: 'myCollection', dimension: 1536, }) await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` **Upstash**: ```ts import { UpstashVector } from '@mastra/upstash' // In upstash they refer to the store as an index const store = new UpstashVector({ id: 'upstash-vector', url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }) // There is no store.createIndex call here, Upstash creates indexes (known as namespaces in Upstash) automatically // when you upsert if that namespace does not exist yet. await store.upsert({ indexName: 'myCollection', // the namespace name in Upstash vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` **Cloudflare**: ```ts import { CloudflareVector } from '@mastra/vectorize' const store = new CloudflareVector({ id: 'cloudflare-vector', accountId: process.env.CF_ACCOUNT_ID, apiToken: process.env.CF_API_TOKEN, }) await store.createIndex({ indexName: 'myCollection', dimension: 1536, }) await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` **OpenSearch**: ```ts import { OpenSearchVector } from '@mastra/opensearch' const store = new OpenSearchVector({ id: 'opensearch', node: process.env.OPENSEARCH_URL }) await store.createIndex({ indexName: 'my-collection', dimension: 1536, }) await store.upsert({ indexName: 'my-collection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` **Elasticsearch**: ```ts import { ElasticSearchVector } from '@mastra/elasticsearch' const store = new ElasticSearchVector({ id: 'elasticsearch-vector', url: process.env.ELASTICSEARCH_URL, auth: { apiKey: process.env.ELASTICSEARCH_API_KEY, }, }) await store.createIndex({ indexName: 'my-collection', dimension: 1536, }) await store.upsert({ indexName: 'my-collection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` ### 使用 Elasticsearch 如需詳細設定指引及最佳做法,請參閱 [Elasticsearch 官方文件](https://www.elastic.co/docs/solutions/search/get-started)。 **Couchbase**: ```ts import { CouchbaseVector } from '@mastra/couchbase' const store = new CouchbaseVector({ id: 'couchbase-vector', connectionString: process.env.COUCHBASE_CONNECTION_STRING, username: process.env.COUCHBASE_USERNAME, password: process.env.COUCHBASE_PASSWORD, bucketName: process.env.COUCHBASE_BUCKET, scopeName: process.env.COUCHBASE_SCOPE, collectionName: process.env.COUCHBASE_COLLECTION, }) await store.createIndex({ indexName: 'myCollection', dimension: 1536, }) await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` **Lance**: ```ts import { LanceVectorStore } from '@mastra/lance' const store = await LanceVectorStore.create('/path/to/db') await store.createIndex({ tableName: 'myVectors', indexName: 'myCollection', dimension: 1536, }) await store.upsert({ tableName: 'myVectors', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` ### 使用 LanceDB LanceDB 是以 Lance 欄式格式建構的嵌入式向量資料庫,適合本機開發或雲端部署。 如需詳細設定指引及最佳做法,請參閱 [LanceDB 官方文件](https://lancedb.github.io/lancedb/)。 **S3 Vectors**: ```ts import { S3Vectors } from '@mastra/s3vectors' const store = new S3Vectors({ id: 's3-vectors', vectorBucketName: 'my-vector-bucket', clientConfig: { region: 'us-east-1', }, nonFilterableMetadataKeys: ['content'], }) await store.createIndex({ indexName: 'my-index', dimension: 1536, }) await store.upsert({ indexName: 'my-index', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }) ``` ## 使用向量儲存 初始化後,所有向量儲存均使用相同介面來建立索引、upsert 嵌入向量及進行查詢。 ### 建立索引 儲存嵌入向量前,你需要建立維度大小與嵌入模型相符的索引: ```ts // Create an index with dimension 1536 (for text-embedding-3-small) await store.createIndex({ indexName: 'myCollection', dimension: 1536, }) ``` 維度大小必須與所選嵌入模型的輸出維度相符。常見維度大小包括: - `OpenAI text-embedding-3-small`:1536 維(或自訂,例如 256) - `Cohere embed-multilingual-v3`:1024 維 - `VoyageAI voyage-3.5`:1024 維(或自訂為 256、512、1024、2048) - `Google gemini-embedding-001`:768 維(或自訂) > **注意:** 索引建立後便無法變更維度。如要使用其他模型,請刪除索引,然後以新的維度大小重新建立。 ### 資料庫命名規則 每個向量資料庫都會對索引及集合套用特定命名慣例,以確保兼容性並避免衝突。 **MongoDB**: 集合(索引)名稱必須: - 以字母或底線開頭 - 長度不超過 120 位元組 - 只包含字母、數字、底線或句點 - 不可包含 `$` 或空字符 - 範例:`my_collection.123` 有效 - 範例:`my-index` 無效(包含連字號) - 範例:`My$Collection` 無效(包含 `$`) **PgVector**: 索引名稱必須: - 以字母或底線開頭 - 只包含字母、數字及底線 - 範例:`my_index_123` 有效 - 範例:`my-index` 無效(包含連字號) **OracleDB**: 索引名稱是 Mastra 邏輯名稱。OracleDB 會在內部將每個邏輯索引對應至實體 Oracle 資料表。 邏輯索引名稱必須: - 不可為空白 - 不超過 512 個字符 - 在向量索引的整個生命週期內保持不變 - 範例:`my_collection_123` 有效 - 範例:`customer-support/docs:v1` 有效,並會對應至安全的 Oracle 資料表名稱 **Pinecone**: 索引名稱必須: - 只使用小寫字母、數字及連字號 - 不包含句點(句點用於 DNS 路由) - 不使用非拉丁字符或表情符號 - 與項目 ID 合計少於 52 個字符 - 範例:`my-index-123` 有效 - 範例:`my.index` 無效(包含句點) **Qdrant**: 集合名稱必須: - 長度為 1 至 255 個字符 - 不包含以下任何特殊字符: - `< > : " / \ | ? *` - 空字符(`\0`) - 單元分隔符(`\u{1F}`) - 範例:`my_collection_123` 有效 - 範例:`my/collection` 無效(包含斜線) **Chroma**: 集合名稱必須: - 長度為 3 至 63 個字符 - 以字母或數字開頭及結尾 - 只包含字母、數字、底線或連字號 - 不包含連續句點(..) - 不可是有效的 IPv4 位址 - 範例:`my-collection-123` 有效 - 範例:`my..collection` 無效(包含連續句點) **Astra**: 集合名稱必須: - 不可為空白 - 不超過 48 個字符 - 只包含字母、數字及底線 - 範例:`my_collection_123` 有效 - 範例:`my-collection` 無效(包含連字號) **libSQL**: 索引名稱必須: - 以字母或底線開頭 - 只包含字母、數字及底線 - 範例:`my_index_123` 有效 - 範例:`my-index` 無效(包含連字號) **Upstash**: 命名空間名稱必須: - 長度為 2 至 100 個字符 - 只包含: - 英數字符(a-z、A-Z、0-9) - 底線、連字號、句點 - 不以特殊字符(\_、-、.)開頭或結尾 - 可以區分大小寫 - 範例:`MyNamespace123` 有效 - 範例:`_namespace` 無效(以底線開頭) **Cloudflare**: 索引名稱必須: - 以字母開頭 - 少於 32 個字符 - 只包含小寫 ASCII 字母、數字及連字號 - 使用連字號取代空格 - 範例:`my-index-123` 有效 - 範例:`My_Index` 無效(包含大寫字母及底線) **OpenSearch**: 索引名稱必須: - 只使用小寫字母 - 不以底線或連字號開頭 - 不包含空格、逗號 - 不包含特殊字符(例如 `:`、`"`、`*`、`+`、`/`、`\`、`|`、`?`、`#`、`>`、`<`) - 範例:`my-index-123` 有效 - 範例:`My_Index` 無效(包含大寫字母) - 範例:`_myindex` 無效(以底線開頭) **Elasticsearch**: 索引名稱必須: - 只使用小寫字母 - 不超過 255 位元組(包括多位元組字符) - 不以底線、連字號或加號開頭 - 不包含空格、逗號 - 不包含特殊字符(例如 `:`、`"`、`*`、`+`、`/`、`\`、`|`、`?`、`#`、`>`、`<`) - 不可是 "." 或 ".." - 不以 "." 開頭(除系統/隱藏索引外,此用法已棄用) - 範例:`my-index-123` 有效 - 範例:`My_Index` 無效(包含大寫字母) - 範例:`_myindex` 無效(以底線開頭) - 範例:`.myindex` 無效(以句點開頭,已棄用) **S3 Vectors**: 索引名稱必須: - 在同一向量儲存貯體內保持唯一 - 長度為 3 至 63 個字符 - 只使用小寫字母(`a–z`)、數字(`0–9`)、連字號(`-`)及句點(`.`) - 以字母或數字開頭及結尾 - 範例:`my-index.123` 有效 - 範例:`my_index` 無效(包含底線) - 範例:`-myindex` 無效(以連字號開頭) - 範例:`myindex-` 無效(以連字號結尾) - 範例:`MyIndex` 無效(包含大寫字母) ### Upsert 嵌入向量 建立索引後,你可以將嵌入向量連同其基本元資料一起儲存: ```ts // Store embeddings with their corresponding metadata await store.upsert({ indexName: 'myCollection', // index name vectors: embeddings, // array of embedding vectors metadata: chunks.map(chunk => ({ text: chunk.text, // The original text content id: chunk.id, // Optional unique identifier })), }) ``` upsert 操作會: - 接收嵌入向量陣列及其對應的元資料 - 如向量使用相同 ID,便更新現有向量 - 如向量尚未存在,便建立新向量 - 自動分批處理大型資料集 ## 加入元資料 向量儲存支援豐富的元資料(任何可序列化為 JSON 的欄位),以供篩選及整理。由於元資料不採用固定結構描述,請使用一致的欄位命名,以免查詢結果不符合預期。 > **注意:** 元資料對向量儲存非常重要。沒有元資料,你只會有數值嵌入向量,無法傳回原文或篩選結果。請至少將來源文字儲存為元資料。 ```ts // Store embeddings with rich metadata for better organization and filtering await store.upsert({ indexName: 'myCollection', vectors: embeddings, metadata: chunks.map(chunk => ({ // Basic content text: chunk.text, id: chunk.id, // Document organization source: chunk.source, category: chunk.category, // Temporal metadata createdAt: new Date().toISOString(), version: '1.0', // Custom fields language: chunk.language, author: chunk.author, confidenceScore: chunk.score, })), }) ``` 元資料的主要注意事項: - 嚴格統一欄位命名——例如 'category' 與 'Category' 不一致會影響查詢 - 只加入你打算用於篩選或排序的欄位——額外欄位會增加負擔 - 加入時間戳記(例如 'createdAt'、'lastUpdated')以追蹤內容時效 ## 刪除向量 建構 RAG 應用程式時,文件遭刪除或更新後,通常需要清理過時向量。Mastra 提供 `deleteVectors` 方法,支援按元資料篩選條件刪除向量,讓你輕鬆移除與特定文件相關的所有嵌入向量。 ### 按元資料篩選條件刪除 最常見的使用情境,是在使用者刪除特定文件時,同時刪除該文件的所有向量: ```ts // Delete all vectors for a specific document await store.deleteVectors({ indexName: 'myCollection', filter: { docId: 'document-123' }, }) ``` 這在以下情況特別實用: - 使用者刪除文件,而你需要移除其所有區塊 - 你正為文件重新建立索引,並希望先移除舊向量 - 你需要清理特定使用者或租戶的向量 ### 刪除多份文件 你亦可使用複合篩選條件,刪除符合多項條件的向量: ```ts // Delete all vectors for multiple documents await store.deleteVectors({ indexName: 'myCollection', filter: { docId: { $in: ['doc-1', 'doc-2', 'doc-3'] }, }, }) // Delete vectors for a specific user's documents await store.deleteVectors({ indexName: 'myCollection', filter: { $and: [{ userId: 'user-123' }, { status: 'archived' }], }, }) ``` ### 按向量 ID 刪除 如要刪除特定向量 ID,可直接傳入這些 ID: ```ts // Delete specific vectors by their IDs await store.deleteVectors({ indexName: 'myCollection', ids: ['vec-1', 'vec-2', 'vec-3'], }) ``` ## 最佳做法 - 大量插入前先建立索引 - 大量插入時使用批次操作(upsert 方法會自動分批處理) - 只儲存你會用於查詢的元資料 - 確保嵌入向量維度與模型相符(例如 `text-embedding-3-small` 使用 1536 維)