> Discover all available pages from the documentation index: https://mastra.zisheng.pro/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)。 ### 将 VoyageAI 与 MongoDB 配合使用 MongoDB 可与针对检索任务优化的 VoyageAI 嵌入模型无缝配合使用。完整示例和专用模型请参阅 [VoyageAI 嵌入文档](https://mastra.zisheng.pro/models/embeddings)和 [MongoDB 向量参考](https://mastra.zisheng.pro/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/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 })), }) ``` ### 将 PostgreSQL 与 pgvector 配合使用 对于已经使用 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 维(也可以自定义) > **注意:** 索引创建后无法更改维度。要使用不同模型,请删除索引,并使用新的维度大小重新创建。 ### 数据库命名规则 每个向量数据库都会对索引和集合实施特定命名约定,以确保兼容性并防止冲突。 **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**: 索引名称必须: - 在同一向量 bucket 中必须唯一 - 长度为 3–63 个字符 - 只能使用小写字母 (`a–z`), numbers (`0–9`), hyphens (`-`), and dots (`.`) - 以字母或数字开头和结尾 - 示例:`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。 ```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)