벡터 DB(Vector Database)는 최근 몇 년 사이 생성형 AI와 고차원 벡터 검색이 주류가 되면서 급부상한 기술 중 하나다. 여러 개념적인 학습을 마친 뒤, 실제로 손에 익히기 위해 직접 사용해본 두 가지 벡터 DB 툴이 있다. 바로 Qdrant와 Faiss다. 이 글에서는 두 도구를 직접 실습한 경험을 바탕으로 벡터 DB의 실체를 보다 현실감 있게 전달하고자 한다.
Qdrant는 Rust로 작성된 고성능 벡터 검색 엔진이며, 설치가 간편하고 RESTful API를 통해 쉽게 벡터 컬렉션을 관리할 수 있다. Python 클라이언트도 제공되지만, 나는 일부러 REST API를 직접 호출하면서 내부 동작을 더 잘 이해하려고 했다.
Qdrant는 Docker로 아주 쉽게 실행할 수 있다:
docker run -p 6333:6333 qdrant/qdrant
기본적으로 6333 포트에서 REST API 서버가 실행된다. 이후 Postman 또는 requests
모듈을 이용해 다음과 같은 작업을 수행했다.
POST /collections/my_vectors
{
"vectors": {
"size": 128,
"distance": "Cosine"
}
}
여기서 size
는 벡터 차원 수를, distance
는 유사도 함수로 코사인 유사도를 사용하도록 설정했다. 이처럼 Qdrant는 사용자 정의 유사도 기반 검색을 매우 직관적으로 구성할 수 있도록 한다.
PUT /collections/my_vectors/points?wait=true
{
"points": [
{
"id": 1,
"vector": [0.1, 0.2, ..., 0.128],
"payload": {
"category": "science"
}
}
]
}
벡터와 함께 payload도 저장할 수 있다. 이 payload는 이후 필터링 조건으로 사용할 수 있다. 예를 들어 "category가 science인 벡터 중 가장 유사한 것"처럼 질의할 수 있다.
POST /collections/my_vectors/points/search
{
"vector": [0.1, 0.2, ..., 0.128],
"top": 5,
"with_payload": true
}
벡터 하나를 기준으로 가장 가까운 5개의 벡터를 반환한다. 실제로 API를 호출해보면 응답 속도가 상당히 빠르며, payload까지 함께 확인할 수 있어 매우 실용적이다.
Faiss는 Facebook AI Research에서 개발한 라이브러리로, C++ 기반이지만 Python API를 통해 고차원 벡터 검색을 매우 빠르게 수행할 수 있다. 특히 in-memory 방식으로 작동해 실시간 추천 시스템이나 임베딩 검색에 자주 사용된다.
import faiss
import numpy as np
d = 128 # 벡터 차원
nb = 1000 # 벡터 개수
xb = np.random.random((nb, d)).astype('float32')
index = faiss.IndexFlatL2(d) # L2 유사도 기반
index.add(xb)
IndexFlatL2는 기본적인 유클리디안 거리 기반의 인덱스이다. 실제로는 IVF, HNSW, PQ 등 다양한 인덱싱 기법도 사용할 수 있다.
xq = np.random.random((5, d)).astype('float32')
D, I = index.search(xq, 3) # 쿼리 5개에 대해 top-3 검색
D
는 거리(distance) 배열, I
는 인덱스(index) 배열을 반환한다. 놀랍게도 수천 개의 벡터에 대해서도 검색이 ms 단위로 수행된다. 그만큼 실시간 검색에 적합하다.
Qdrant와 Faiss 모두 벡터 DB라는 기술을 실제로 구현해보는 데 최적의 도구였다. Qdrant는 API 기반으로 빠른 프로토타이핑에 유리했고, Faiss는 고성능의 로컬 인메모리 검색을 체험할 수 있었다.
이 실습을 통해 얻은 가장 큰 깨달음은 "벡터 DB는 이제 실험적인 기술이 아니라, 손쉽게 적용 가능한 실용 기술"이라는 점이다. 추천 시스템, 유사 검색, RAG 기반 LLM 어플리케이션을 만들고자 한다면, 이 두 도구 중 하나는 반드시 손에 익혀둘 필요가 있다.