📎

Qdrant 벡터 검색, 원리부터 이해하기

개요

이 글은 Qdrant 벡터 데이터베이스의 동작 원리를 설명합니다(15-20분 소요).
설치 방법이나 코드 예제보다는 내부 메커니즘과 설계 철학을 다룹니다.
이 글에서 다루는 내용은 다음과 같습니다.
  • 벡터 검색이 전통적인 DB와 근본적으로 다른 이유
  • Qdrant의 핵심 구조와 알고리즘 원리
  • 성능 문제나 설계 선택에서 올바른 판단을 내리기 위한 기반
 

벡터 검색이 필요한 이유

전통적인 데이터베이스는 정확한 값 일치나 범위 검색에 최적화되어 있습니다. WHERE price > 1000 같은 쿼리는 효율적으로 처리하지만, "이 상품과 비슷한 다른 상품"을 찾기는 어렵습니다. 이때 벡터 검색을 사용합니다.
벡터 검색은 의미의 유사성을 계산합니다. "노트북"과 "랩탑"이 다른 단어지만 의미가 비슷하다는 것을 이해하고, 두 검색어에 대해 유사한 결과를 반환합니다. 이는 추천 시스템, 의미 기반 검색, 이미지 유사도 검색 등에서 핵심적인 기능입니다.
하지만 기존 DB 인덱스로는 유사도 검색이 불가능합니다. B-Tree나 Hash 인덱스는 정확한 값을 찾는 데 특화되어 있기 때문입니다. 벡터 데이터베이스는 이 문제를 해결하기 위해 완전히 다른 접근 방식을 사용합니다.
 

벡터가 의미를 표현하는 방식

벡터는 숫자의 배열입니다. 예를 들어 [0.2, -0.5, 0.8, ...] 같은 형태입니다. 각 차원은 의미의 특정 측면을 인코딩합니다.
임베딩 모델은 텍스트, 이미지, 오디오를 벡터로 변환합니다. 예를 들어 "강아지"라는 단어는 768차원 벡터로 표현될 수 있습니다. 중요한 점은 의미가 비슷한 단어들이 벡터 공간에서 가까운 위치에 배치된다는 것입니다.
이 원리는 문장과 문서에도 적용됩니다. "고양이가 나무에 올라갔다"와 "새끼 고양이가 큰 나무 위로 올라갔다"는 표현은 다르지만 벡터로 변환하면 매우 가까운 위치에 놓입니다.
임베딩 모델의 품질이 검색 품질을 결정합니다. 같은 Qdrant를 사용해도 어떤 임베딩 모델을 선택하느냐에 따라 결과가 달라집니다. OpenAI의 text-embedding-3, Cohere의 embed-v3, 오픈소스 BERT 계열 모델 등 선택지가 많습니다.
 

Qdrant의 데이터 모델

Qdrant는 벡터를 포인트라는 단위로 저장합니다. 각 포인트는 다음을 포함합니다.
  • ID - 고유 식별자
  • Vector - 실제 벡터 데이터
  • Payload - 메타데이터 (JSON 형태)
여러 포인트를 모은 것이 컬렉션입니다. 컬렉션은 RDB의 테이블과 유사하지만 스키마가 더 유연합니다. 컬렉션 생성 시 필수로 정해야 하는 것은 벡터 차원과 거리 메트릭뿐입니다.
Qdrant는 다중 벡터를 지원합니다. 하나의 포인트에 여러 벡터를 저장할 수 있다는 뜻입니다. 예를 들어 제품 설명에 대한 벡터와 제품 이미지에 대한 벡터를 함께 저장하고, 검색 시 두 벡터를 모두 고려할 수 있습니다.
페이로드는 필터링에 사용됩니다. "가격 1만원 이상이면서 벡터 유사도가 높은 제품"처럼 벡터 검색과 전통적인 필터를 결합할 수 있습니다. 이를 위해 페이로드 필드에 인덱스를 걸 수 있습니다.
 

유사도 계산과 거리 메트릭

벡터 간 유사도는 거리로 측정합니다. Qdrant는 세 가지 거리 메트릭을 지원합니다.
코사인 유사도는 벡터 간 각도를 측정합니다. 벡터의 크기는 무시하고 방향만 봅니다. 텍스트 검색에서 가장 많이 사용됩니다. 두 문서의 주제가 비슷하면 벡터 방향이 비슷하기 때문입니다.
유클리드 거리는 두 점 사이의 직선 거리입니다. 벡터의 크기도 중요할 때 사용합니다. 이미지 임베딩처럼 절대적인 값이 의미를 가질 때 적합합니다.
내적은 벡터의 방향과 크기를 모두 고려합니다. 추천 시스템에서 선호도 점수를 계산할 때 유용합니다.
메트릭 선택은 임베딩 모델과 연결됩니다. 대부분의 임베딩 모델은 특정 메트릭에 최적화되어 있습니다. OpenAI 모델은 코사인 유사도, 일부 비전 모델은 유클리드 거리를 권장합니다.
거리 계산은 계산 비용이 큽니다. 100만 개 벡터와 모두 비교하면 시간이 너무 오래 걸립니다. 여기서 인덱스가 필요해집니다.
 

HNSW 인덱스의 동작 원리

Qdrant는 HNSW(Hierarchical Navigable Small World) 알고리즘을 사용합니다. HNSW는 근사 최근접 이웃 탐색 알고리즘입니다.
핵심 아이디어는 계층적 그래프 구조입니다. 여러 레이어로 나뉜 그래프가 있고, 상위 레이어는 성긴 연결, 하위 레이어는 조밀한 연결을 가집니다. 검색은 최상위 레이어에서 시작해 대략적인 영역을 찾은 뒤, 하위 레이어로 내려가며 정확한 이웃을 찾습니다.
이 방식은 정확도와 속도의 균형을 맞춥니다. 모든 벡터를 비교하지 않아도 높은 확률로 가장 가까운 이웃을 찾습니다. 수백만 벡터에서도 밀리초 단위로 검색이 가능한 이유입니다.
HNSW의 파라미터는 두 가지가 핵심입니다.
  • m - 각 노드의 연결 수. 크면 정확도는 높아지지만 메모리와 색인 시간이 증가합니다.
  • ef_construct - 색인 구축 시 탐색 범위. 크면 색인 품질이 좋아지지만 구축 시간이 늘어납니다.
이 파라미터들은 트레이드오프 관계입니다. 정확도, 속도, 메모리 중 무엇을 우선할지에 따라 조정합니다.
 

쿼리 처리 파이프라인

검색 쿼리가 들어오면 Qdrant는 다음 순서로 처리합니다.
1단계 - 벡터 인덱스 검색
: HNSW 인덱스를 사용해 쿼리 벡터와 가장 가까운 후보를 찾습니다. 이 단계에서 대략 몇십 개에서 몇백 개의 후보가 선정됩니다.
2단계 - 필터 적용
: 페이로드 조건이 있다면 후보 중에서 필터링합니다. 여기서 중요한 선택이 있습니다. 필터를 먼저 적용할지, 벡터 검색을 먼저 할지입니다. Qdrant는 상황에 따라 자동으로 최적 전략을 선택합니다.
3단계 - 정확한 거리 계산
: 후보들에 대해 정확한 거리를 다시 계산합니다. HNSW는 근사 알고리즘이므로 최종 순위는 정확한 계산으로 확정합니다.
4단계 - 결과 정렬 및 반환
: 점수 순으로 정렬하고 요청한 개수만큼 반환합니다.
이 과정에서 Qdrant는 여러 최적화를 수행합니다. 예를 들어 필터 조건이 매우 제한적이면(전체의 1% 미만) 필터를 먼저 적용한 후 벡터 검색을 수행합니다. 반대로 필터가 느슨하면 벡터 검색을 먼저 합니다.
배치 검색도 최적화됩니다. 여러 쿼리를 한 번에 보내면 공통 계산을 재사용하여 처리 속도를 높입니다.
 

마무리하며…

Qdrant의 핵심은 HNSW 인덱스와 유연한 쿼리 처리입니다. 벡터 검색의 속도와 정확도를 균형있게 제공하면서, 전통적인 필터링과 결합할 수 있는 구조를 갖췄습니다.
거리 메트릭을 임베딩 모델에 맞게 선택하고, HNSW 파라미터를 요구사항에 맞게 조정하고, 쿼리 전략을 데이터 특성에 맞게 설계할 수 있습니다.