> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-TW/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-TW/models/embeddings)及 [MongoDB 向量參考文件](https://mastra.zisheng.pro/zh-TW/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-TW/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` 欄位,並將 metadata 儲存在 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 維(或自訂) > **警告:** 索引建立後便無法變更維度。若要使用不同模型,請刪除索引,並以新的維度大小重新建立。 ### 資料庫命名規則 各向量資料庫都會對索引與 collection 強制執行特定命名慣例,以確保相容性並避免衝突。 **MongoDB**: Collection(索引)名稱必須: - 以字母或底線開頭 - 長度不得超過 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**: Collection 名稱必須: - 長度必須為 1-255 個字元 - 不得包含以下任何特殊字元: - `< > : " / \ | ? *` - 空字元 (`\0`) - 單元分隔符號 (`\u{1F}`) - 範例:`my_collection_123` 有效 - 範例:`my/collection` 無效(包含斜線) **Chroma**: Collection 名稱必須: - 長度必須為 3-63 個字元 - 以字母或數字開頭及結尾 - 只能包含字母、數字、底線或連字號 - 不得包含連續句點 (..) - 不得為有效的 IPv4 位址 - 範例:`my-collection-123` 有效 - 範例:`my..collection` 無效(包含連續句點) **Astra**: Collection 名稱必須: - 不得為空 - 不得超過 48 個字元 - 只能包含字母、數字及底線 - 範例:`my_collection_123` 有效 - 範例:`my-collection` 無效(包含連字號) **libSQL**: 索引名稱必須: - 以字母或底線開頭 - 只能包含字母、數字及底線 - 範例:`my_index_123` 有效 - 範例:`my-index` 無效(包含連字號) **Upstash**: Namespace 名稱必須: - 長度必須為 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**: 索引名稱必須: - 在同一個向量 bucket 中必須是唯一的 - 長度必須為 3–63 個字元 - 只能使用小寫字母 (`a–z`)、數字 (`0–9`)、連字號 (`-`) 及句點 (`.`) - 以字母或數字開頭及結尾 - 範例:`my-index.123` 有效 - 範例:`my_index` 無效(包含底線) - 範例:`-myindex` 無效(以連字號開頭) - 範例:`myindex-` 無效(以連字號結尾) - 範例:`MyIndex` 無效(包含大寫字母) ### Upsert 嵌入向量 建立索引後,即可儲存嵌入向量及其基本 metadata: ```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 操作會: - 接受嵌入向量陣列及其對應的 metadata - 若向量具有相同 ID,則更新既有向量 - 若向量不存在,則建立新向量 - 自動為大型資料集進行批次處理 ## 新增 metadata 向量儲存支援豐富的 metadata(任何可序列化為 JSON 的欄位),可用於篩選及整理。由於 metadata 不採固定 schema 儲存,請使用一致的欄位命名,以免出現非預期的查詢結果。 > **警告:** Metadata 對向量儲存十分重要。若缺少 metadata,就只會剩下數值嵌入向量,無法傳回原始文字或篩選結果。請務必至少將來源文字儲存為 metadata。 ```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, })), }) ``` Metadata 的主要注意事項: - 嚴格控管欄位命名,例如「category」與「Category」不一致會影響查詢 - 只加入預計用於篩選或排序的欄位,額外欄位會增加負擔 - 加入時間戳記(例如「createdAt」、「lastUpdated」)以追蹤內容新鮮度 ## 刪除向量 建構 RAG 應用程式時,文件刪除或更新後通常需要清除過時向量。Mastra 提供 `deleteVectors` 方法,支援依 metadata 篩選器刪除向量,讓你能直接移除與特定文件相關的所有嵌入向量。 ### 依 Metadata 篩選器刪除 最常見的使用情境是在使用者刪除特定文件時,一併刪除該文件的所有向量: ```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,可以直接傳入: ```ts // Delete specific vectors by their IDs await store.deleteVectors({ indexName: 'myCollection', ids: ['vec-1', 'vec-2', 'vec-3'], }) ``` ## 最佳實務 - 大量插入資料前先建立索引 - 大量插入資料時使用批次操作(upsert 方法會自動處理批次) - 只儲存查詢時會使用的 metadata - 讓嵌入向量維度符合模型(例如 `text-embedding-3-small` 為 1536)