ベクトルデータベースへの埋め込みの保存
埋め込みを生成したら、ベクトル類似性検索に対応するデータベースへ保存する必要があります。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 })),
})
PostgreSQL と pgvector を使用する
pgvector 拡張を導入した PostgreSQL は、すでに 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 バイト以内にする
- 英字、数字、アンダースコア、ドットのみを使用する
$または null 文字を含めない- 例:
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 文字にする
- 次の特殊文字を含めない:
< > : " / \ | ? *- null 文字(
\0) - Unit Separator(
\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 が分かっている場合は、直接渡せます。
// Delete specific vectors by their IDs
await store.deleteVectors({
indexName: 'myCollection',
ids: ['vec-1', 'vec-2', 'vec-3'],
})
ベストプラクティスベストプラクティスへの直接リンク
- 一括挿入の前にインデックスを作成する
- 大量に挿入する場合はバッチ操作を使用する(upsert メソッドがバッチ処理を自動的に行う)
- クエリに使用するメタデータだけを保存する
- 埋め込みの次元数をモデルに合わせる(例:
text-embedding-3-smallは 1536)