| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- Spring
- Spring Boot
- github
- 마이바티스
- react
- Java
- 리팩토링
- kubernetes
- 파이썬
- 스프링
- 쿠버네티스
- 리액트
- MySQL
- springboot
- DataGridView
- 자바
- design pattern
- c#
- 도커
- docker
- mybatis
- machine-learning
- Kotlin
- Python
- 코틀린
- 스프링부트
- AWS
- git
- Winform
- VOA
- Today
- Total
보뇨 다이어리
벡터 DB 기초 정리 (백엔드 개발자 관점) 본문
일반 RDB는 잘 알지만 벡터 DB는 처음 접하는 백엔드 개발자를 위한 정리
1. 벡터 DB란 무엇인가
1.1 저장되는 데이터
핵심: 벡터(숫자 배열) + 원본 데이터(payload)
{
"id": "doc_1",
"vector": [0.024, -0.183, 0.471, ..., 0.092], // 차원수만큼 (예: 1024개)
"payload": {
"title": "K8s 네트워킹",
"content": "CNI는 컨테이너 네트워크를 ...",
"category": "infra"
}
}
- vector: 임베딩 모델이 텍스트를 받아 만들어낸 숫자 배열
- payload: 원본 데이터 및 메타데이터 (필터링, 결과 표시용)
1.2 임베딩의 핵심 원리
의미가 비슷한 텍스트는 비슷한 벡터로 변환됨.
"K8s 네트워킹" → [0.02, -0.18, 0.47, ...]
"쿠버네티스 통신" → [0.03, -0.19, 0.45, ...] ← 거의 비슷한 벡터
"오늘 점심 뭐 먹지" → [0.81, 0.32, -0.15, ...] ← 완전 다른 벡터
1.3 RDB와의 비교
항목 일반 RDB 벡터 DB
| 데이터 형태 | 정형 (row/column) | 벡터 + payload |
| 쿼리 방식 | 정확한 매칭 (=, LIKE, JOIN) | 유사도 검색 (ANN) |
| 인덱스 | B-tree, Hash | HNSW, IVF 같은 ANN 인덱스 |
| 결과 | 조건을 만족하는 전체 | Top-K (보통 5~20개) |
| 강점 | 트랜잭션, JOIN, 집계 | 의미 검색, 유사 항목 찾기 |
| 약점 | 의미 기반 검색 불가 | 트랜잭션/JOIN 거의 없음 |
2. 검색 동작 방식
2.1 검색 흐름
1. 사용자 쿼리 입력
"쿠버네티스 네트워크 어떻게 동작해?"
2. 같은 임베딩 모델로 벡터화
→ [0.025, -0.182, ...]
3. 이 벡터와 거리가 가까운 Top-K개 검색
4. 결과 반환
[
{ "id": "doc_1", "score": 0.92, "payload": {...} },
{ "id": "doc_7", "score": 0.87, "payload": {...} },
{ "id": "doc_3", "score": 0.81, "payload": {...} }
]
2.2 Top-K의 의미
K = 가져올 개수. SQL의 LIMIT과 유사한 개념.
-- RDB 비유
SELECT * FROM documents
ORDER BY similarity DESC
LIMIT 5; -- Top-5
벡터 검색에서는 거의 항상 Top-K 방식.
- 모든 문서가 어느 정도 점수를 가짐 (정확 일치 개념이 없음)
- "조건 만족하는 전체"가 아니라 "가장 가까운 N개"가 자연스러움
참고: Recall@7 같은 지표의 @7은 Top-7으로 검색했을 때 정답 문서가 포함된 비율을 의미.
2.3 거리 계산 방법
각 항목값을 ±1씩 시도하는 게 아니라, 수식 한 방으로 계산.
코사인 유사도 (가장 흔함)
두 벡터가 이루는 각도를 측정.
쿼리 벡터 Q = [0.2, 0.5, 0.1]
문서 벡터 A = [0.3, 0.4, 0.2]
문서 벡터 B = [-0.8, 0.1, 0.6]
코사인 유사도 = (Q · A) / (|Q| × |A|)
= 내적 / (각 벡터의 길이 곱)
Q vs A → 0.95 (방향이 비슷함, 가까움)
Q vs B → 0.12 (방향이 다름, 멈)
주요 거리 측정 방식
방식 설명 언제 씀
| Cosine | 각도 기반 | 텍스트 임베딩 (가장 흔함) |
| Dot Product | 내적 | 정규화된 벡터 (빠름) |
| Euclidean (L2) | 직선 거리 | 이미지 임베딩 등 |
정규화된 벡터(bge, OpenAI 등)에서는 Cosine = Dot Product라 Dot가 더 빠름.
2.4 Top-K를 빠르게 뽑는 방법: ANN
Brute Force (전수 검색)
모든 벡터와 거리 계산 → 정확하지만 느림 (1억 개면 수 초).
ANN (Approximate Nearest Neighbor)
정확도를 약간 포기하고 속도를 얻음. 실제 운영에서 사용하는 방식.
HNSW (Hierarchical Navigable Small World) - 가장 보편적
Layer 2 (성김): A ─────────── E
│ │
Layer 1 (중간): A ─── C ───── E ─── G
│ │ │ │
Layer 0 (촘촘): A-B-C-D-E-F-G-H-I-J-K-L ← 모든 벡터
비유:
"서울역에서 가장 가까운 카페 5개" 찾기
1. "서울 어디?" (대륙 단위)
2. "중구 근처?" (도시 단위)
3. "서울역 근처?" (동네 단위)
4. 그 동네에서만 정밀 비교
→ 1억 개에서도 수 ms 안에 검색 가능.
주요 인덱스 알고리즘
알고리즘 특징 지원 DB
| HNSW | 그래프 기반, 빠르고 정확, 메모리 많이 씀 | Qdrant, Milvus, pgvector, Weaviate |
| IVF | 클러스터링 기반, 메모리 효율 | Milvus, FAISS, pgvector |
| IVF-PQ | IVF + 양자화 (벡터 압축) | Milvus, FAISS |
| DiskANN | 디스크 기반, 초대용량 | Milvus, Azure |
대부분 HNSW가 기본값. 수억 건 이상부터 IVF-PQ 등 압축 방식 고려.
3. 임베딩 모델과 벡터 DB의 분리
[임베딩 모델] [벡터 DB]
텍스트 → 벡터 생성 → 벡터 저장 + 검색
(bge-m3, OpenAI 등) (Qdrant, Milvus 등)
- 임베딩 모델: 모델마다 많이 다름
- 벡터 DB 검색 방식: 대체로 표준화되어 있음
3.1 임베딩 모델의 차이점
차원 수 차이
모델 차원
| OpenAI text-embedding-3-small | 1536 |
| OpenAI text-embedding-3-large | 3072 |
| bge-m3 | 1024 |
| bge-small-en | 384 |
| Cohere embed-v3 | 1024 |
차원이 다르면 DB 스키마 자체가 달라짐. 모델 바꾸면 컬렉션 재생성 필요.
의미 공간이 다름 (중요)
같은 문장이라도 모델마다 완전히 다른 벡터가 나옴.
"K8s 네트워킹"
OpenAI: [0.024, -0.183, 0.471, ..., 0.092] (1536차원)
bge-m3: [-0.512, 0.087, -0.231, ..., 0.405] (1024차원)
임베딩 모델을 섞어 쓰면 안 됨:
❌ 문서는 OpenAI로 임베딩 → 검색 쿼리는 bge-m3
→ 의미 공간이 달라서 거리 계산이 무의미
✅ 문서도 OpenAI, 쿼리도 OpenAI
✅ 문서도 bge-m3, 쿼리도 bge-m3
정규화 여부
- 정규화된 벡터: 길이가 1 → 내적이 곧 코사인 유사도라 빠름
- 정규화 안 된 벡터: 코사인 쓰려면 길이 계산 추가 필요
bge 계열, OpenAI는 정규화 출력. 일부 오픈소스 모델은 직접 정규화 필요.
특수 임베딩 형태 (bge-m3 예시)
타입 형태 특징
| Dense | [0.02, -0.18, ...] 1024개 | 일반 의미 임베딩 |
| Sparse | {30522: 0.5, 1024: 0.3, ...} | BM25처럼 키워드 기반 |
| ColBERT (multi-vector) | 토큰마다 벡터 (N × 1024) | 정밀 매칭, 무거움 |
3.2 벡터 DB의 표준화
거리 계산 방식과 인덱스 알고리즘은 DB가 달라도 대체로 동일.
주요 벡터 DB 비교
DB 특징
| Qdrant | Rust, 단순한 API, payload 필터링 강함 |
| Milvus | 대규모/분산, K8s 친화적 |
| pgvector | PostgreSQL 확장, 기존 RDB와 함께 |
| Weaviate | GraphQL, 모듈식 |
| Elasticsearch | 검색엔진 + 벡터, BM25 통합 쉬움 |
DB 선택은 인덱스 알고리즘보다 **운영 환경(K8s, 규모, 기존 스택)**에 좌우됨.
4. 언제 벡터 DB를 쓰는가
4.1 벡터 DB가 적합한 경우
- RAG (Retrieval-Augmented Generation): LLM에 컨텍스트로 넣을 문서 검색
- 추천 시스템: "이 상품과 비슷한 거"
- 이미지/음성 검색: 의미적으로 유사한 멀티미디어
- 중복 탐지, 표절 검사: 표현이 달라도 유사한 내용 찾기
- 이상 탐지: 정상 패턴 벡터와 멀리 떨어진 데이터
4.2 일반 DB를 써야 하는 경우
- 사용자, 주문, 결제 같은 트랜잭션 데이터
- 정확한 조건 검색이 필요한 경우
- 집계, 통계, 리포팅
4.3 실무 아키텍처: 둘 다 같이 사용
[원본 문서]
├→ RDB / Object Storage: 원본 보관, 메타데이터, 권한
└→ Vector DB: 청크별 임베딩 + 검색용 payload
검색 시:
1. 사용자 쿼리 → 벡터화
2. Vector DB에서 Top-K 청크 검색
3. (필요하면) RDB에서 원본/권한 확인
4. LLM에 컨텍스트로 전달
하이브리드 검색: BM25(키워드 매칭) + 벡터 검색(의미 매칭)을 RRF 등으로 결합해 정확도 향상.
5. 실무 의사결정 포인트
- 임베딩 모델 선택이 가장 중요 — 검색 품질의 대부분이 여기서 결정됨
- 벡터 DB는 운영 환경에 맞춰 선택 — K8s 환경, 데이터 규모, 기존 스택 고려
- 모델 변경 시 전체 재임베딩 필수 — 운영 비용이 크므로 신중히 선택
- 하이브리드 검색 고려 — 의미 검색만으로 부족한 경우 BM25 등과 결합
6. 추가 학습 키워드
- HNSW 파라미터 튜닝: M, ef_construction, ef_search
- 양자화 (Quantization): 메모리 절약 기법 (Scalar, Product Quantization)
- Reranker: 1차 검색 후 정밀 재정렬 (Cross-encoder 기반)
- 청킹 전략: 문서를 어떻게 분할할지 (fixed-size, semantic, recursive)
- 임베딩 모델 선택 기준: 도메인/언어/문서 길이/비용
- MTEB 벤치마크: 임베딩 모델 성능 비교 지표
'컴퓨터 관련 > 개발지식 정보' 카테고리의 다른 글
| 소프트웨어 설계의 정석 (3) | 2024.11.18 |
|---|---|
| The security token included in the request is invalid 발생할때 에러 해결 (0) | 2023.05.01 |
| Five lines of code 책을 읽고나서 (0) | 2023.04.16 |
| 리팩토링에 관한 다양한 방법들중 쓸만한 규칙 (0) | 2023.04.16 |
| 실무중 가장 많이 사용할 linux 커맨드 리스트 (0) | 2022.05.22 |