본문 바로가기
카테고리 없음

문서 검색을 위한 VectorDB 활용법: HNSW와 IVF-Flat 인덱싱 기법 차이점

by 북더기 2025. 3. 20.

문서 검색 시스템에서, 대량의 텍스트 데이터를 효과적으로 처리하려면 벡터 데이터베이스(VectorDB)를 활용하는 것이 중요합니다. 전통적으로 사용되던 키워드 기반 검색 방식은 특정 단어가 포함된 문서를 찾는 데 적합하지만, 의미적으로 유사한 문서를 찾기 위해서는 벡터 검색이 필요합니다. 이를 위해서 많이 사용되는 인덱싱 기법이 HNSW(Hierarchical Navigable Small World)와 IVF-Flat(Inverted File System with Flat Quantization)입니다. 두 가지의 방식은 각기 다른 방식으로 벡터를 저장하고 검색 속도를 최적화합니다.

HNSW 인덱싱 기법

HNSW는 그래프 기반의 최근접 이웃 탐색(ANN, Approximate Nearest Neighbor) 알고리즘 중에 하나로, 높은 검색 속도와 정확도를 제공합니다. 이 방법은 데이터 간의 연결 관계를 계층적 그래프 구조로 구성하여 빠른 검색이 가능하도록 합니다.

HNSW는 아래와 같은 원리로 작동을 하게 됩니다.

  • 각 데이터 포인트는 그래프 내에서 다른 포인트들과 연결됩니다.
  • 연결은 여러 계층(Level)으로 나뉘며, 높은 레벨일수록 데이터 밀도가 낮고, 낮은 레벨일수록 세밀한 탐색이 가능합니다.
  • 검색 시에는 가장 높은 레벨에서 시작하여 점차 낮은 레벨로 이동하며 최적의 근접 벡터를 찾습니다.

이 방식은 탐색 경로를 최적화하여 속도를 높이는 것이 핵심입니다. 일반적으로 brute-force 방식으로 모든 벡터를 비교하는 것보다 훨씬 빠르며, 검색 정확도도 더 높게 됩니다.

HNSW는 Faiss, Annoy, ScaNN 등 다양한 라이브러리에서 지원되며, 특히 Faiss에서의 구현이 널리 사용됩니다. 아래의 코드에서 예제를 확인해 볼 수 있겠습니다.


import faiss
import numpy as np

# 128차원 벡터 10,000개 생성
dimension = 128
num_vectors = 10000
vectors = np.random.random((num_vectors, dimension)).astype('float32')

# HNSW 인덱스 생성
index = faiss.IndexHNSWFlat(dimension, 32)  # 32는 M 파라미터 (연결 개수)
index.add(vectors)

# 검색 수행
query = np.random.random((1, dimension)).astype('float32')
distances, indices = index.search(query, 5)  # 가장 가까운 5개 검색

print(indices)

HNSW는 고차원 데이터에서도 성능이 뛰어나며, 메모리를 상대적으로 많이 사용하지만 빠른 검색 속도를 제공합니다.

IVF-Flat 인덱싱 기법

IVF-Flat은 Inverted File System(IVF)과 Flat Quantization을 조합한 방식으로, 데이터셋을 여러 개의 클러스터로 나눈 후 검색 속도를 높이는 방식입니다. IVF는 먼저 k-means 알고리즘을 사용하여 데이터 포인트를 여러 개의 클러스터로 나누고, 검색 시에는 전체 데이터셋을 탐색하는 대신 특정 클러스터 내에서만 검색을 수행합니다.

IVF-Flat 방식의 주요 특징은 다음과 같습니다.

  • 데이터를 k-means 기반으로 미리 클러스터링하여 저장합니다.
  • 검색 시, 입력 벡터와 가장 유사한 클러스터를 찾고 해당 클러스터 내에서만 최근접 이웃 탐색을 수행합니다.
  • Flat Quantization을 사용하여 압축하지 않고 원본 벡터 값을 유지합니다.

IVF-Flat은 HNSW보다 메모리를 덜 사용하지만, 검색 속도는 클러스터 개수에 따라 달라집니다. 클러스터 개수가 너무 많으면 검색 속도가 느려지고, 너무 적으면 정확도가 낮아질 수 있습니다.

또한, Faiss를 활용한 IVF-Flat 구현 예제는 다음과 같습니다.


import faiss
import numpy as np

# 128차원 벡터 10,000개 생성
dimension = 128
num_vectors = 10000
vectors = np.random.random((num_vectors, dimension)).astype('float32')

# IVF-Flat 인덱스 생성 (클러스터 개수 100)
quantizer = faiss.IndexFlatL2(dimension)
index = faiss.IndexIVFFlat(quantizer, dimension, 100)
index.train(vectors)  # 클러스터 학습
index.add(vectors)

# 검색 수행
query = np.random.random((1, dimension)).astype('float32')
distances, indices = index.search(query, 5)  # 가장 가까운 5개 검색

print(indices)

IVF-Flat 방식은 검색 속도를 개선하면서도 원본 벡터 정보를 유지할 수 있는 장점이 있지만, 클러스터링 단계가 필요하여 사전 학습 과정이 필요합니다.

HNSW vs IVF-Flat, 어떤 방식이 더 적합할까?

HNSW와 IVF-Flat은 각각 장단점이 있기 때문에 사용 목적에 따라 적절한 방식을 선택하는 것이 중요합니다.

HNSW는 검색 속도와 정확도가 뛰어나지만, 메모리 사용량이 많다는 단점이 있습니다. 따라서, 빠른 검색이 필요한 실시간 애플리케이션이나 대규모 데이터셋에서 높은 정확도가 요구되는 경우 적합합니다.

IVF-Flat은 메모리 사용량을 줄이면서도 검색 속도를 최적화할 수 있는 방식으로, 대량의 데이터가 있는 경우 효과적입니다. 다만, 클러스터 개수를 잘 설정해야 성능이 최적화되므로 데이터 특성에 맞게 실험이 필요합니다.

결론적으로, 데이터 크기와 검색 속도를 고려하여 선택하는 것이 중요합니다. 실시간 검색과 높은 정확도가 필요한 경우 HNSW를, 대규모 데이터셋에서 메모리 효율을 고려해야 한다면 IVF-Flat을 선택하는 것이 적절하다고 생각합니다.