ベクトルデータベースへの埋め込みの保存
埋め込みを生成した後、ベクトル類似性検索をサポートするデータベースに保存する必要があります。Mastraは、さまざまなベクトルデータベース間で埋め込みを保存およびクエリするための一貫したインターフェースを提供します。
サポートされているデータベース
Pg Vector
import { PgVector } from '@mastra/pg';
const store = new PgVector({ 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の利用
pgvector拡張機能を持つPostgreSQLは、すでにPostgreSQLを使用しており、インフラストラクチャの複雑さを最小限に抑えたいチームにとって良いソリューションです。 詳細なセットアップ手順とベストプラクティスについては、公式pgvectorリポジトリ を参照してください。
ベクターストレージの使用
初期化が完了すると、すべてのベクターストアはインデックスの作成、埋め込みのアップサート、クエリの実行に同じインターフェースを共有します。
インデックスの作成
埋め込みを保存する前に、使用する埋め込みモデルに適した次元数でインデックスを作成する必要があります。
// 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次元
- Google
text-embedding-004
: 768次元(またはカスタム)
重要: インデックスの次元数は作成後に変更できません。別のモデルを使用する場合は、インデックスを削除し、新しい次元数で再作成してください。
データベースの命名規則
各ベクターデータベースは、互換性を確保し競合を防ぐために、インデックスやコレクションの命名規則を定めています。
Pg Vector
インデックス名は以下の条件を満たす必要があります:
- 文字またはアンダースコアで始まる
- 文字、数字、アンダースコアのみを含む
- 例:
my_index_123
は有効 - 例:
my-index
は無効(ハイフンを含む)
埋め込みのアップサート
インデックスを作成した後、基本的なメタデータと一緒に埋め込みを保存できます:
// 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を共有する既存のベクトルがある場合は更新します
- 存在しない場合は新しいベクトルを作成します
- 大規模なデータセットに対して自動的にバッチ処理を行います
異なるベクトルストアでの埋め込みのupsertの完全な例については、Upsert Embeddingsガイドを参照してください。
メタデータの追加
ベクトルストアはフィルタリングと整理のためのリッチなメタデータ(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」)を追加する
ベストプラクティス
- 大量挿入の前にインデックスを作成する
- 大量挿入にはバッチ操作を使用する(upsertメソッドは自動的にバッチ処理を行います)
- クエリを実行する予定のメタデータのみを保存する
- 埋め込みの次元数をモデルに合わせる(例:
text-embedding-3-small
の場合は1536)