在向量数据库中存储嵌入
生成嵌入后,需要将其存储到支持向量相似度搜索的数据库中。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 官方文档。
将 VoyageAI 与 MongoDB 配合使用
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 })),
})
将 PostgreSQL 与 pgvector 配合使用
对于已经使用 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 维(也可以自定义)
索引创建后无法更改维度。要使用不同模型,请删除索引,并使用新的维度大小重新创建。
数据库命名规则数据库命名规则的直接链接
每个向量数据库都会对索引和集合实施特定命名约定,以确保兼容性并防止冲突。
- 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无效(以点开头,此用法已弃用)
索引名称必须:
- 在同一向量 bucket 中必须唯一
- 长度为 3–63 个字符
- 只能使用小写字母 (
a–z), numbers (0–9), hyphens (-), and dots (.) - 以字母或数字开头和结尾
- 示例:
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。
// 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)