在向量資料庫儲存嵌入向量
產生嵌入向量後,你需要將它們儲存在支援向量相似度搜尋的資料庫中。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 欄中,並以 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 維(或自訂)
索引建立後便無法變更維度。如要使用其他模型,請刪除索引,然後以新的維度大小重新建立。
資料庫命名規則資料庫命名規則 的直接連結
每個向量資料庫都會對索引及集合套用特定命名慣例,以確保兼容性並避免衝突。
- MongoDB
- PgVector
- OracleDB
- Pinecone
- Qdrant
- Chroma
- Astra
- libSQL
- Upstash
- Cloudflare
- OpenSearch
- Elasticsearch
- S3 Vectors
集合(索引)名稱必須:
- 以字母或底線開頭
- 長度不超過 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無效(包含句點)
- 範例:
集合名稱必須:
- 長度為 1 至 255 個字符
- 不包含以下任何特殊字符:
< > : " / \ | ? *- 空字符(
\0) - 單元分隔符(
\u{1F})
- 範例:
my_collection_123有效 - 範例:
my/collection無效(包含斜線)
集合名稱必須:
- 長度為 3 至 63 個字符
- 以字母或數字開頭及結尾
- 只包含字母、數字、底線或連字號
- 不包含連續句點(..)
- 不可是有效的 IPv4 位址
- 範例:
my-collection-123有效 - 範例:
my..collection無效(包含連續句點)
集合名稱必須:
- 不可為空白
- 不超過 48 個字符
- 只包含字母、數字及底線
- 範例:
my_collection_123有效 - 範例:
my-collection無效(包含連字號)
索引名稱必須:
- 以字母或底線開頭
- 只包含字母、數字及底線
- 範例:
my_index_123有效 - 範例:
my-index無效(包含連字號)
命名空間名稱必須:
- 長度為 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無效(以句點開頭,已棄用)
索引名稱必須:
- 在同一向量儲存貯體內保持唯一
- 長度為 3 至 63 個字符
- 只使用小寫字母(
a–z)、數字(0–9)、連字號(-)及句點(.) - 以字母或數字開頭及結尾
- 範例:
my-index.123有效 - 範例:
my_index無效(包含底線) - 範例:
-myindex無效(以連字號開頭) - 範例:
myindex-無效(以連字號結尾) - 範例:
MyIndex無效(包含大寫字母)
Upsert 嵌入向量Upsert 嵌入向量 的直接連結
建立索引後,你可以將嵌入向量連同其基本元資料一起儲存:
// 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 的欄位),以供篩選及整理。由於元資料不採用固定結構描述,請使用一致的欄位命名,以免查詢結果不符合預期。
元資料對向量儲存非常重要。沒有元資料,你只會有數值嵌入向量,無法傳回原文或篩選結果。請至少將來源文字儲存為元資料。
// 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 方法,支援按元資料篩選條件刪除向量,讓你輕鬆移除與特定文件相關的所有嵌入向量。
按元資料篩選條件刪除按元資料篩選條件刪除 的直接連結
最常見的使用情境,是在使用者刪除特定文件時,同時刪除該文件的所有向量:
// 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,可直接傳入這些 ID:
// Delete specific vectors by their IDs
await store.deleteVectors({
indexName: 'myCollection',
ids: ['vec-1', 'vec-2', 'vec-3'],
})
最佳做法最佳做法 的直接連結
- 大量插入前先建立索引
- 大量插入時使用批次操作(upsert 方法會自動分批處理)
- 只儲存你會用於查詢的元資料
- 確保嵌入向量維度與模型相符(例如
text-embedding-3-small使用 1536 維)