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