벡터 데이터베이스에 임베딩 저장
임베딩을 생성한 후에는 벡터 유사성 검색을 지원하는 데이터베이스에 저장해야 합니다. 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 벡터 검색 사용
자세한 설정 지침과 모범 사례는 다음을 참조하세요.official MongoDB Atlas Vector Search documentation.
MongoDB와 함께 VoyageAI 사용
MongoDB는 검색 작업에 최적화된 VoyageAI의 임베딩 Model과 원활하게 작동합니다. 전체 예제와 특수 Model을 보려면 다음을 참조하세요.VoyageAI embeddings documentation and MongoDB vector reference.
하이브리드 검색(벡터 + 전체 텍스트)
MongoDB는 서버 측을 사용하여 BM25 전체 텍스트 검색과 벡터 유사성을 융합하는 하이브리드 검색을 지원합니다.$rankFusion (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,
})
참조MongoDB vector reference for details on createSearchIndex(), textQuery(), and hybridQuery().
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 사용
pgVector 확장이 포함된 PostgreSQL은 인프라 복잡성을 최소화하려는 PostgreSQL을 이미 사용하고 있는 팀에게 좋은 솔루션입니다. 자세한 설정 지침과 모범 사례는 다음을 참조하세요.official pgvector repository.
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 데이터베이스 벡터 검색 사용
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 })),
})
엘라스틱서치 사용
자세한 설정 지침과 모범 사례는 다음을 참조하세요.official Elasticsearch documentation.
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 컬럼 형식을 기반으로 구축된 임베디드 벡터 데이터베이스입니다. 자세한 설정 지침과 모범 사례는 다음을 참조하세요.official LanceDB documentation.
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 })),
})
벡터 저장소 사용벡터 저장소 사용에 대한 직접 링크
일단 초기화되면 모든 벡터 저장소는 인덱스 생성, 임베딩 업데이트 및 쿼리를 위해 동일한 인터페이스를 공유합니다.
인덱스 생성인덱스 생성에 대한 직접 링크
임베딩을 저장하기 전에 임베딩 Model에 적합한 차원 크기로 인덱스를 생성해야 합니다.
// Create an index with dimension 1536 (for text-embedding-3-small)
await store.createIndex({
indexName: 'myCollection',
dimension: 1536,
})
차원 크기는 선택한 임베딩 Model의 출력 차원과 일치해야 합니다. 일반적인 치수 크기는 다음과 같습니다.
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 치수(또는 사용자 정의)
인덱스 차원은 생성 후에 변경할 수 없습니다. 다른 Model을 사용하려면 인덱스를 삭제하고 새 차원 크기로 다시 생성하세요.
데이터베이스 명명 규칙데이터베이스 명명 규칙에 대한 직접 링크
각 벡터 데이터베이스는 호환성을 보장하고 충돌을 방지하기 위해 인덱스 및 컬렉션에 대한 특정 명명 규칙을 적용합니다.
- MongoDB
- PgVector
- OracleDB
- Pinecone
- Qdrant
- Chroma
- Astra
- libSQL
- Upstash
- Cloudflare
- OpenSearch
- Elasticsearch
- S3 Vectors
컬렉션(색인) 이름은 다음과 같아야 합니다.
- 문자 또는 밑줄로 시작
- 최대 120바이트 길이
- 문자, 숫자, 밑줄, 점만 포함하세요.
- 포함할 수 없음
$or the null character - 예:
my_collection.123is valid - 예:
my-indexis not valid (contains hyphen) - 예:
My$Collectionis not valid (contains$)
인덱스 이름은 다음을 충족해야 합니다.
- 문자 또는 밑줄로 시작
- 문자, 숫자, 밑줄만 포함
- 예:
my_index_123is valid - 예:
my-indexis not valid (contains hyphen)
인덱스 이름은 논리적 마스트라 이름입니다. OracleDB는 내부적으로 각 논리적 인덱스를 물리적 Oracle 테이블에 매핑합니다.
논리적 인덱스 이름은 다음을 충족해야 합니다.
- 비어 있지 않음
- 512자 이하여야 합니다.
- 벡터 인덱스의 수명 동안 안정적이어야 합니다.
- 예:
my_collection_123is valid - 예:
customer-support/docs:v1가 유효하며 안전한 Oracle 테이블 이름으로 매핑됩니다
인덱스 이름은 다음을 충족해야 합니다.
- 소문자, 숫자, 대시만 사용하세요.
- 점을 포함하지 않음(DNS 라우팅에 사용됨)
- 라틴 문자가 아닌 문자나 이모티콘을 사용하지 마세요.
- 프로젝트 ID와 함께 총 길이가 52자 미만이어야 합니다.
- 예:
my-index-123is valid - 예:
my.indexis not valid (contains dot)
- 예:
컬렉션 이름은 다음과 같아야 합니다.
- 길이는 1~255자여야 합니다.
- 다음 특수 문자를 포함하면 안 됩니다.
< > : " / \ | ? *- 널 문자(
\0) - 단위 구분 기호(
\u{1F})
- 예:
my_collection_123is valid - 예:
my/collectionis not valid (contains slash)
컬렉션 이름은 다음과 같아야 합니다.
- 3~63자(영문 기준)여야 합니다.
- 문자나 숫자로 시작하고 끝나세요.
- 문자, 숫자, 밑줄, 하이픈만 포함하세요.
- 연속된 마침표(..)를 포함하지 않습니다.
- 유효한 IPv4 주소가 아닙니다.
- 예:
my-collection-123is valid - 예:
my..collectionis not valid (consecutive periods)
컬렉션 이름은 다음과 같아야 합니다.
- 비어 있지 않음
- 48자 이하여야 합니다.
- 문자, 숫자, 밑줄만 포함
- 예:
my_collection_123is valid - 예:
my-collectionis not valid (contains hyphen)
인덱스 이름은 다음을 충족해야 합니다.
- 문자 또는 밑줄로 시작
- 문자, 숫자, 밑줄만 포함
- 예:
my_index_123is valid - 예:
my-indexis not valid (contains hyphen)
네임스페이스 이름은 다음을 충족해야 합니다.
- 길이는 2~100자여야 합니다.
- 다음만 포함:
- 영숫자(a-z, A-Z, 0-9)
- 밑줄, 하이픈, 점
- 특수 문자(_, -, .)로 시작하거나 끝나서는 안 됩니다.
- 대소문자를 구분할 수 있습니다.
- 예:
MyNamespace123is valid - 예:
_namespaceis not valid (starts with underscore)
인덱스 이름은 다음을 충족해야 합니다.
- 편지로 시작하세요
- 32자(영문 기준) 미만이어야 합니다.
- 소문자 ASCII 문자, 숫자, 대시만 포함합니다.
- 공백 대신 대시를 사용하세요.
- 예:
my-index-123is valid - 예:
My_Indexis not valid (uppercase and underscore)
인덱스 이름은 다음을 충족해야 합니다.
- 소문자만 사용하세요.
- 밑줄이나 하이픈으로 시작하지 마세요.
- 공백, 쉼표를 포함할 수 없습니다.
- 특수 문자를 포함할 수 없습니다(예:
:,",*,+,/,\,|,?,#,>,<) - 예:
my-index-123is valid - 예:
My_Indexis not valid (contains uppercase letters) - 예:
_myindexis not valid (begins with underscore)
인덱스 이름은 다음을 충족해야 합니다.
- 소문자만 사용하세요.
- 255바이트를 초과할 수 없습니다(멀티바이트 문자 계산).
- 밑줄, 하이픈 또는 더하기 기호로 시작하지 마세요.
- 공백, 쉼표를 포함할 수 없습니다.
- 특수 문자를 포함할 수 없습니다(예:
:,",*,+,/,\,|,?,#,>,<) - "."가 아닙니다. 또는 ".."
- "."으로 시작하지 않음 (시스템/숨겨진 인덱스를 제외하고 더 이상 사용되지 않음)
- 예:
my-index-123is valid - 예:
My_Indexis not valid (contains uppercase letters) - 예:
_myindexis not valid (begins with underscore) - 예:
.myindexis not valid (begins with dot, deprecated)
인덱스 이름은 다음을 충족해야 합니다.
- 동일한 벡터 버킷 내에서 고유해야 합니다.
- 길이는 3~63자여야 합니다.
- 소문자만 사용하세요(
a–z), numbers (0–9), hyphens (-), and dots (.) - 문자나 숫자로 시작하고 끝나요
- 예:
my-index.123is valid - 예:
my_indexis not valid (contains underscore) - 예:
-myindexis not valid (begins with hyphen) - 예:
myindex-is not valid (ends with hyphen) - 예:
MyIndexis not valid (contains uppercase letters)
임베딩 업서트임베딩 업서트에 대한 직접 링크
인덱스를 생성한 후 기본 메타데이터와 함께 임베딩을 저장할 수 있습니다.
// 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,
})),
})
주요 메타데이터 고려 사항:
- 필드 이름 지정을 엄격하게 하세요. '카테고리'와 '카테고리' 같은 불일치는 쿼리에 영향을 미칩니다.
- 필터링하거나 정렬하려는 필드만 포함합니다. 추가 필드는 오버헤드를 추가합니다.
- 콘텐츠 최신성을 추적하려면 타임스탬프(예: 'createdAt', 'lastUpdated')를 추가하세요.
벡터 삭제벡터 삭제에 대한 직접 링크
RAG 애플리케이션을 구축할 때 문서가 삭제되거나 업데이트될 때 오래된 벡터를 정리해야 하는 경우가 많습니다. 마스트라가 제공하는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 메서드는 자동으로 일괄 처리를 처리합니다.
- 쿼리할 메타데이터만 저장하세요.
- 임베딩 크기를 Model에 일치시키세요(예: 1536
text-embedding-3-small)