🤖 1. DB가 “의미"를 이해하려면?

WHERE name = '강아지'는 쉽습니다. 하지만 **“귀여운 동물 사진 찾아줘”**는 어떻게 쿼리할까요? 컴퓨터는 이미지를 모릅니다. 그래서 AI 모델을 통해 **숫자 배열(Vector)**로 바꿉니다.

"강아지" → [0.1, 0.9, 0.3, ...]   (1536차원)
"고양이" → [0.2, 0.8, 0.4, ...]
"자동차" → [0.9, 0.1, 0.0, ...]

이 숫자들의 **거리(Distance)**가 가까우면 의미가 비슷한 겁니다. 이를 Embedding이라 합니다.

거리 측정 방식

방식수식특징사용 시나리오
Cosine Similarity1 - cos(θ)방향(의미) 비교, 크기 무시텍스트 유사도, 추천
Euclidean (L2)√Σ(aᵢ-bᵢ)²절대 거리 비교이미지 검색, 클러스터링
Dot ProductΣ(aᵢ×bᵢ)정규화된 벡터에서 Cosine과 동일대규모 검색 (연산 빠름)

실무 팁: 텍스트 임베딩(OpenAI, Cohere 등)은 이미 정규화되어 있어서 Cosine과 Dot Product 결과가 동일합니다. Dot Product가 연산이 더 가벼워 대규모에서 유리합니다.


🎯 2. KNN vs ANN — 정확도와 속도의 트레이드오프

KNN (K-Nearest Neighbors) — Brute Force

모든 벡터와 거리를 계산합니다. 100% 정확하지만, 데이터가 100만 개면 100만 번 계산해야 합니다.

  • 시간 복잡도: O(n × d) (n: 벡터 수, d: 차원)
  • 1억 벡터 × 1536차원 → 수 초~수십 초 소요

ANN (Approximate Nearest Neighbors) — 근사 검색

“99%만 정확해도 100배 빠르면 낫지 않나?” — ANN의 핵심 철학입니다. Recall@k라는 지표로 정확도를 측정합니다:

Recall@10 = (ANN이 찾은 Top 10 ∩ 실제 Top 10) / 10

실무에서 Recall@10 ≥ 0.95면 충분하고, 이를 1ms 이내에 달성하는 것이 목표입니다.


🕸️ 3. HNSW: 고차원 공간의 내비게이션

**HNSW (Hierarchical Navigable Small World)**는 가장 널리 쓰이는 ANN 알고리즘입니다.

계층형 그래프 구조

마치 고속도로 → 국도 → 골목길을 타는 것과 같습니다.

graph TD
    subgraph Layer 2 [Top Layer: Express Highway]
    A1((Entry)) --> B1((Jump))
    end
    
    subgraph Layer 1 [Middle Layer: Main Road]
    B1 --> C1((Search)) --> D1((Search))
    end
    
    subgraph Layer 0 [Bottom Layer: Local Street — 모든 데이터]
    D1 --> E1((Target)) --> F1((Neighbor))
    end
    
    A1 -.->|Go Down| B1
    D1 -.->|Go Down| E1
  1. Layer 2 (Top): 극소수 노드만 존재. 대략적인 위치로 점프합니다.
  2. Layer 1 (Mid): 더 많은 노드. Greedy Search로 목표에 접근합니다.
  3. Layer 0 (Base): 모든 데이터가 연결. 최종적으로 가장 가까운 이웃을 정밀 탐색합니다.

HNSW 핵심 파라미터

파라미터의미기본값올리면내리면
M각 노드의 최대 이웃 수16Recall↑, 메모리↑, 빌드↑메모리↓, Recall↓
efConstruction인덱스 빌드 시 탐색 범위200인덱스 품질↑, 빌드 시간↑빌드 빠름, 품질↓
efSearch검색 시 탐색 범위50~200Recall↑, 지연↑빠름, Recall↓

튜닝 가이드

# Milvus 예시: 파라미터 조합별 벤치마크
index_params = {
    "index_type": "HNSW",
    "metric_type": "IP",  # Inner Product (= Dot Product)
    "params": {
        "M": 32,              # 높은 Recall 필요 시
        "efConstruction": 256  # 빌드 시간 여유 있을 때
    }
}

search_params = {
    "metric_type": "IP",
    "params": {
        "ef": 128  # Recall@10 > 0.98 목표
    }
}

튜닝 순서: efSearch를 먼저 조정(런타임 변경 가능) → 부족하면 MefConstruction 올려서 리빌드


📊 4. 다른 ANN 알고리즘들

HNSW만 있는 게 아닙니다. 데이터 규모와 제약 조건에 따라 다른 선택지가 있습니다.

IVF (Inverted File Index)

벡터 공간을 **K개 클러스터(Voronoi Cell)**로 나누고, 검색 시 가장 가까운 nprobe개 클러스터만 탐색합니다.

전체 100만 벡터 → 1,000개 클러스터
검색 시 nprobe=10 → 10개 클러스터의 1만 벡터만 비교
→ 100배 빨라짐
  • 장점: 메모리 효율이 좋음 (인덱스가 작음)
  • 단점: 클러스터 경계에 걸친 벡터를 놓칠 수 있음

PQ (Product Quantization) — 벡터 압축

1536차원 벡터를 **192개 서브벡터(8차원씩)**로 쪼갠 뒤, 각 서브벡터를 256개 코드북 중 하나로 대체합니다.

원본: 1536차원 × 4byte(float32) = 6,144 byte/벡터
PQ:   192개 서브코드 × 1byte    =   192 byte/벡터  → 32배 압축!
  • 장점: 메모리를 극적으로 줄임 → 10억 벡터도 RAM에 적재 가능
  • 단점: 압축 손실로 Recall 약간 감소

IVF-PQ 조합

실무에서 대규모(1억+) 데이터셋은 IVF로 후보를 줄이고, PQ로 메모리를 절약하는 IVF-PQ 조합을 많이 씁니다.

알고리즘 선택 가이드

데이터 규모메모리 여유권장 인덱스
< 100만충분HNSW (최고 Recall, 가장 단순)
100만 ~ 1억보통HNSW 또는 IVF-HNSW
> 1억부족IVF-PQ 또는 ScaNN
실시간 업데이트 중요HNSW (삽입/삭제 유연)
배치 빌드 후 읽기 전용IVF-PQ (빌드 후 고정)

🧠 5. RAG 아키텍처 심화 — 백엔드 엔지니어의 역할

LLM(ChatGPT)은 최신 정보를 모릅니다. 그래서 백엔드가 “컨닝 페이퍼"를 줘야 합니다. 이를 **RAG (Retrieval-Augmented Generation)**라 합니다.

sequenceDiagram
    participant User
    participant Backend
    participant VectorDB
    participant LLM
    
    User->>Backend: "우리 회사의 환불 규정이 뭐야?"
    Backend->>Backend: 질문을 벡터로 변환 (Embedding API)
    Backend->>VectorDB: ANN Search (Top K=5)
    VectorDB-->>Backend: [환불 규정 문서 청크 5개 + 유사도 점수]
    
    Backend->>Backend: 유사도 임계값 필터링 (score > 0.75)
    Backend->>Backend: 프롬프트 조립 (System + Context + Question)
    Backend->>LLM: 프롬프트 전송
    LLM-->>Backend: 답변 생성
    Backend-->>User: 최종 답변 + 출처 문서 링크

Chunking 전략 — 검색 품질의 80%를 결정

문서를 잘게 쪼개는 방식이 검색 정확도를 좌우합니다.

전략방식장점단점
Fixed Size512토큰씩 고정 분할구현 단순문맥 단절
Overlap512토큰 + 50토큰 오버랩경계 정보 보존저장 공간 증가
Semantic문단/섹션 단위의미 단위 유지크기 불균일
Recursive큰 단위 → 작은 단위 순 시도유연성구현 복잡
Parent-Child작은 청크로 검색, 큰 청크를 LLM에 전달정밀 검색 + 풍부한 컨텍스트2단계 조회 필요
# LangChain: Recursive Character Splitter (실무 권장)
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n\n", "\n", ". ", " ", ""],  # 우선순위 순
    length_function=len
)
chunks = splitter.split_text(document_text)

검색 품질 개선 테크닉

1. Hybrid Search (키워드 + 벡터)

최종 점수 = α × BM25_score + (1-α) × vector_similarity
  • “RFC 7231” 같은 고유명사는 키워드 검색이 더 정확
  • “에러 처리 패턴” 같은 의미 검색은 벡터가 우수
  • α = 0.3~0.5 권장

2. Reranking — 2단계 정밀 검증

1단계: Vector DB에서 Top 20 후보 추출 (빠르지만 거칠음)
2단계: Cross-Encoder로 (질문, 청크) 쌍을 정밀 점수화 → Top 5 선택
  • Cross-Encoder는 느리지만 정확도가 높음
  • Cohere Rerank, BGE-reranker 등 사용

3. Query Expansion / HyDE

원본 질문: "환불 규정"
→ LLM이 가상 답변 생성: "고객은 구매일로부터 14일 이내에..."
→ 가상 답변을 임베딩해서 검색 (실제 답변과 더 유사한 벡터)

🏗️ 6. Vector DB 비교 — 어떤 걸 쓸까?

DB타입HNSWIVF-PQHybrid Search특징
PineconeManaged SaaS운영 부담 0, 비용 높음
MilvusSelf-hosted / Zilliz Cloud고성능, 풍부한 인덱스, 학습곡선
WeaviateSelf-hosted / CloudGraphQL API, 모듈화
QdrantSelf-hosted / CloudRust 기반, 필터링 성능 우수
pgvectorPostgreSQL 확장SQL 통합기존 PG 인프라 활용, 소규모에 적합
ChromaDB임베디드프로토타이핑/로컬 개발용

선택 체크리스트

  • 10만 이하 + 이미 PostgreSQL 사용 중pgvector
  • 100만 이하 + 빠른 프로토타입 → Pinecone 또는 Qdrant Cloud
  • 1억 이상 + 자체 인프라 → Milvus
  • 필터 조건이 복잡 → Qdrant (payload 필터 성능 우수)

🔧 7. 운영 체크리스트

인덱스 빌드

  • 데이터 규모에 맞는 인덱스 타입 선택 (HNSW vs IVF-PQ)
  • 빌드 후 Recall@10 벤치마크 수행 (목표: ≥ 0.95)
  • 인덱스 빌드 시간이 SLA를 초과하지 않는지 확인

검색 성능

  • P99 지연 시간 모니터링 (목표: < 50ms)
  • efSearch / nprobe 튜닝으로 Recall-Latency 균형 조정
  • 동시 검색 부하 테스트 수행

데이터 관리

  • 임베딩 모델 변경 시 전체 리인덱싱 필요 (모델 버전 관리)
  • 문서 업데이트/삭제 시 벡터도 함께 갱신
  • 메타데이터 필터 인덱스 설정 (날짜, 카테고리 등)

비용

  • 벡터 차원 수 × 데이터 수 × float32(4B) = 최소 메모리 산정
  • 예: 100만 × 1536차원 × 4B = 5.7GB (인덱스 오버헤드 별도)

📚 8. 연관 학습


요약

개념핵심
Embedding의미를 고차원 좌표(벡터)로 변환
ANN정확도를 약간 희생하고 속도를 수십~수백 배 향상
HNSW계층형 그래프로 위→아래 좁혀가는 고속 검색. 가장 범용적
IVF-PQ클러스터링 + 압축으로 대규모 데이터셋 처리
RAGVector DB + LLM을 연결하는 아키텍처
Chunking문서 분할 전략이 검색 품질의 80%를 결정
Hybrid SearchBM25 + 벡터 결합으로 고유명사/의미 검색 모두 커버