在向量資料庫中儲存嵌入向量
產生嵌入向量後,必須將其儲存在支援向量相似度搜尋的資料庫中。Mastra 提供一致的介面,可跨向量資料庫儲存及查詢嵌入向量。
支援的資料庫「支援的資料庫」的直接連結
- MongoDB
- PgVector
- OracleDB
- Pinecone
- Qdrant
- Chroma
- Astra
- libSQL
- Upstash
- Cloudflare
- OpenSearch
- Elasticsearch
- Couchbase
- Lance
- S3 Vectors
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 官方文件。
搭配 MongoDB 使用 VoyageAI
MongoDB 可順暢搭配針對檢索任務最佳化的 VoyageAI 嵌入模型。如需完整範例與專用模型,請參閱 VoyageAI 嵌入文件及 MongoDB 向量參考文件。
混合搜尋(向量 + 全文)
MongoDB 支援混合搜尋,可透過伺服器端 $rankFusion 融合向量相似度與 BM25 全文搜尋(需要 MongoDB >= 8.0;自 8.1 起全面提供,Atlas 8.0.x 亦已啟用)。若要結合語意檢索與關鍵字檢索,此功能十分實用:
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 向量參考文件。
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 官方儲存庫。
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 索引。
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 })),
})
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 })),
})
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 })),
})
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 })),
})
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 })),
})
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 })),
})
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 })),
})
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 })),
})
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 官方文件。
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 })),
})
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 官方文件。
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 嵌入向量及查詢。
建立索引「建立索引」的直接連結
儲存嵌入向量之前,必須先建立維度大小符合嵌入模型的索引:
// 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
- PgVector
- OracleDB
- Pinecone
- Qdrant
- Chroma
- Astra
- libSQL
- Upstash
- Cloudflare
- OpenSearch
- Elasticsearch
- S3 Vectors
Collection(索引)名稱必須:
- 以字母或底線開頭
- 長度不得超過 120 位元組
- 只能包含字母、數字、底線或句點
- 不得包含
$或空字元 - 範例:
my_collection.123有效 - 範例:
my-index無效(包含連字號) - 範例:
My$Collection無效(包含$)
索引名稱必須:
- 以字母或底線開頭
- 只能包含字母、數字及底線
- 範例:
my_index_123有效 - 範例:
my-index無效(包含連字號)
索引名稱是 Mastra 的邏輯名稱。OracleDB 會在內部將每個邏輯索引對應至實體 Oracle 資料表。
邏輯索引名稱必須:
- 不得為空
- 不得超過 512 個字元
- 在向量索引的生命週期內保持不變
- 範例:
my_collection_123有效 - 範例:
customer-support/docs:v1有效,並會對應至安全的 Oracle 資料表名稱
索引名稱必須:
- 只能使用小寫字母、數字及連字號
- 不得包含句點(用於 DNS 路由)
- 不得使用非拉丁字元或表情符號
- 與專案 ID 合計的長度必須少於 52 個字元
- 範例:
my-index-123有效 - 範例:
my.index無效(包含句點)
- 範例:
Collection 名稱必須:
- 長度必須為 1-255 個字元
- 不得包含以下任何特殊字元:
< > : " / \ | ? *- 空字元 (
\0) - 單元分隔符號 (
\u{1F})
- 範例:
my_collection_123有效 - 範例:
my/collection無效(包含斜線)
Collection 名稱必須:
- 長度必須為 3-63 個字元
- 以字母或數字開頭及結尾
- 只能包含字母、數字、底線或連字號
- 不得包含連續句點 (..)
- 不得為有效的 IPv4 位址
- 範例:
my-collection-123有效 - 範例:
my..collection無效(包含連續句點)
Collection 名稱必須:
- 不得為空
- 不得超過 48 個字元
- 只能包含字母、數字及底線
- 範例:
my_collection_123有效 - 範例:
my-collection無效(包含連字號)
索引名稱必須:
- 以字母或底線開頭
- 只能包含字母、數字及底線
- 範例:
my_index_123有效 - 範例:
my-index無效(包含連字號)
Namespace 名稱必須:
- 長度必須為 2-100 個字元
- 只能包含:
- 英數字元(a-z、A-Z、0-9)
- 底線、連字號、句點
- 開頭或結尾不得為特殊字元(_、-、.)
- 可能區分大小寫
- 範例:
MyNamespace123有效 - 範例:
_namespace無效(以底線開頭)
索引名稱必須:
- 以字母開頭
- 必須少於 32 個字元
- 只能包含小寫 ASCII 字母、數字及連字號
- 使用連字號取代空格
- 範例:
my-index-123有效 - 範例:
My_Index無效(包含大寫字母與底線)
索引名稱必須:
- 只能使用小寫字母
- 不得以底線或連字號開頭
- 不得包含空格或逗號
- 不得包含特殊字元(例如
:、"、*、+、/、\、|、?、#、>、<) - 範例:
my-index-123有效 - 範例:
My_Index無效(包含大寫字母) - 範例:
_myindex無效(以底線開頭)
索引名稱必須:
- 只能使用小寫字母
- 不得超過 255 位元組(多位元組字元也計入)
- 不得以底線、連字號或加號開頭
- 不得包含空格或逗號
- 不得包含特殊字元(例如
:、"、*、+、/、\、|、?、#、>、<) - 不得為「.」或「..」
- 不得以「.」開頭(系統/隱藏索引除外,此用法已淘汰)
- 範例:
my-index-123有效 - 範例:
My_Index無效(包含大寫字母) - 範例:
_myindex無效(以底線開頭) - 範例:
.myindex無效(以句點開頭,此用法已淘汰)
索引名稱必須:
- 在同一個向量 bucket 中必須是唯一的
- 長度必須為 3–63 個字元
- 只能使用小寫字母 (
a–z)、數字 (0–9)、連字號 (-) 及句點 (.) - 以字母或數字開頭及結尾
- 範例:
my-index.123有效 - 範例:
my_index無效(包含底線) - 範例:
-myindex無效(以連字號開頭) - 範例:
myindex-無效(以連字號結尾) - 範例:
MyIndex無效(包含大寫字母)
Upsert 嵌入向量「Upsert 嵌入向量」的直接連結
建立索引後,即可儲存嵌入向量及其基本 metadata:
// 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」的直接連結
向量儲存支援豐富的 metadata(任何可序列化為 JSON 的欄位),可用於篩選及整理。由於 metadata 不採固定 schema 儲存,請使用一致的欄位命名,以免出現非預期的查詢結果。
Metadata 對向量儲存十分重要。若缺少 metadata,就只會剩下數值嵌入向量,無法傳回原始文字或篩選結果。請務必至少將來源文字儲存為 metadata。
// 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 篩選器刪除「依 Metadata 篩選器刪除」的直接連結
最常見的使用情境是在使用者刪除特定文件時,一併刪除該文件的所有向量:
// Delete all vectors for a specific document
await store.deleteVectors({
indexName: 'myCollection',
filter: { docId: 'document-123' },
})
此功能特別適合以下情境:
- 使用者刪除文件,而你需要移除其所有片段
- 你正在重新索引文件,並希望先移除舊向量
- 你需要清除特定使用者或租戶的向量
刪除多份文件「刪除多份文件」的直接連結
你也可以使用複雜篩選器,刪除符合多個條件的向量:
// 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,可以直接傳入:
// 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)