How We Vectorize 33.7M Ukrainian Court Decisions via Voyage AI

How We Vectorize 33.7M Ukrainian Court Decisions via Voyage AI

키워드 검색의 한계, 벡터 검색으로 돌파하기

법률 도메인에서 "은행 선납 수수료 반환 판례가 있나요?"라는 질문을 처리할 때, 전통적인 전문 검색(Full-Text Search)은 '수수료'라는 단어가 포함된 수천 건의 문서를 쏟아낸다. 변호사가 원하는 건 그 40개의 판결문을 직접 읽는 게 아니라, 의미적으로 가장 유사한 상위 5건의 판결과 핵심 논리를 즉시 확인하는 것이다.

이를 해결하기 위해 우크라이나 법원 결정문 통합 등록부(EDRSR)의 민사 사건 3,370만 건을 의미론적 벡터로 변환하는 프로젝트가 진행됐다. Voyage AI 임베딩 모델이 판결문의 각 단락을 1,024차원 벡터 공간의 한 점으로 변환하고, 의미적으로 유사한 단락들이 이 공간에서 서로 가깝게 배치된다. 이후 Qdrant에서 kNN 검색으로 가장 관련성 높은 K개의 단락을 즉시 추출할 수 있다.

대규모 파이프라인의 인프라 선택

이 프로젝트의 핵심 과제는 규모 자체다. 민사(CPC) 3,370만 건을 포함해 현재 Qdrant 컬렉션 edrsr_decisions에는 형사·민사·상사·경범죄를 합산한 4,400만 개 이상의 벡터가 저장돼 있다.

단일 EC2 인스턴스로 이를 처리한 선택은 주목할 만하다. 사용된 스펙은 r6a.xlarge(32GB RAM, 2TB gp3 스토리지)다. 메모리 최적화 인스턴스를 선택한 이유는 명확하다. 벡터 인덱싱 과정에서 대량의 데이터를 메모리에 적재해야 하며, Qdrant의 on_disk=true 옵션을 통해 벡터 자체는 디스크에 저장하되 HNSW 인덱스 그래프는 메모리에서 처리하는 구조를 취했다. gp3 스토리지는 gp2 대비 비용 대비 IOPS 효율이 높아 대용량 순차 쓰기가 빈번한 벡터 적재 워크로드에 적합하다.

# Qdrant 컬렉션 설정 예시 (개념적)
vectors_config:
  size: 1024
  distance: Cosine
  on_disk: true   # 벡터를 디스크에 오프로드, RAM 부담 절감
hnsw_config:
  m: 16
  ef_construct: 100

실무에서 마주친 장애물(rakes)

3,370만 건 규모의 파이프라인을 단일 인스턴스에서 운영하면서 여러 실패 사례가 드러났다. 대표적인 문제는 다음과 같다.

  • 메모리 압박: 배치 크기를 과도하게 설정하면 임베딩 처리 중 OOM이 발생. 배치 단위를 조정하고 처리 후 명시적으로 메모리를 해제하는 로직이 필수적이다.
  • 네트워크 타임아웃: 외부 임베딩 API(Voyage AI) 호출 시 재시도 로직과 지수 백오프(exponential backoff)가 없으면 파이프라인이 중간에 멈춘다.
  • 체크포인트 부재: 수천만 건 처리 중 장애 발생 시 처음부터 재시작하는 비용은 치명적이다. 마지막으로 처리된 문서 ID를 영속적으로 기록하는 체크포인트 메커니즘이 반드시 필요하다.
// 체크포인트 패턴 예시
long lastProcessedId = checkpointStore.getLastId();
List<Decision> batch = repository.findByIdGreaterThan(lastProcessedId, BATCH_SIZE);
// 처리 후
checkpointStore.save(batch.getLast().getId());

비용 구조 측면에서도 임베딩 API 호출 비용은 토큰 수에 비례하므로, 법원 결정문의 전체 본문을 통째로 임베딩하기보다 핵심 단락을 청킹(chunking)하여 처리하는 전략이 비용과 검색 품질 양쪽에서 유리하다.

정리

  • 키워드 FTS로 해결 안 되는 의미론적 검색은 1,024차원 벡터 임베딩 + kNN 검색 조합으로 실현 가능하며, 법률·의료 등 전문 도메인에서 특히 효과적이다.
  • 수천만 건 규모의 벡터화 파이프라인에는 체크포인트, 재시도 로직, 배치 크기 조정이 선택이 아닌 필수 설계 요소다.
  • Qdrant의 on_disk=true 옵션과 메모리 최적화 인스턴스 조합은 대규모 벡터 스토리지를 단일 노드에서 운영할 때 비용 효율적인 현실적 대안이다.
Source
Dev.to
원문 보기 →
← 목록으로 돌아가기