벡터 검색

벡터 인덱스는 상호 호환되지 않는다. 대부분의 애플리케이션은 그런 식으로 취급한다.

의미 검색을 구축하는 대부분의 팀은 뒤늦게 똑같은 교훈을 얻게 됩니다. 재현율(recall), 검색 쿼리 지연 시간, 하드웨어 비용을 궁극적으로 좌우하는 것은 임베딩 모델이나 선택한 데이터베이스가 아닙니다. 그것은 바로 벡터 인덱스 설정인데, 이는 대개 초기 단계에 설정되고 거의 다시 검토되지 않습니다.

나쁜 선택이 드러날 때쯤이면 이미 피해는 발생한 후입니다. 리콜(Recall)은 몇 주 동안 표류하고 있습니다. 최대 부하 상태에서 클러스터의 메모리가 고갈됩니다. 일상적으로 보이던 업그레이드가 재작업으로 바뀝니다. 이러한 문제 중 어느 것도 생성 시점에는 나타나지 않으며, 이것이 바로 이 문제들이 계속 발생하는 주된 이유입니다.

따라서 모두가 서둘러 지나치는 단계, 즉 벡터 인덱스를 생성할 때 실제로 무슨 일이 일어나는지, 왜 그 단 하나의 단계가 그토록 큰 비중을 차지하는지, 그리고 잘못된 선택이 어떻게 조용히 운영 장애(프로덕션 인시던트)로 이어질 수 있는지에 대해 잠시 멈추고 살펴볼 가치가 있습니다.

인덱스 생성은 설정이 아니라 약속입니다

벡터 색인을 추가하는 것은 단순한 구조적 변경이 아니며, 학습이 필요합니다. 빌드 프로세스는 데이터를 샘플링하고, 일군의 군집 중심(centroid)을 학습하며, 각 벡터가 어떻게 압축될지 결정하고, 메모리나 디스크에 그래프 구조를 배치합니다. 색인이 구축되면 이러한 결정들은 사실상 그 안에 고정됩니다. 나중에 이를 변경하는 것은 거의 항상 색인을 삭제하고 다시 구축해야 함을 의미합니다. 대규모 데이터셋의 경우, 그러한 재구축은 몇 시간이 걸릴 수 있으며 상당한 양의 CPU와 I/O를 소모합니다.

대부분의 팀이 과소평과하는 부분이 바로 그 점입니다. CREATE 문은 하나의 깔끔한 설정 블록처럼 보입니다. 하지만 그 진정한 역할은 애플리케이션을 메모리 모델, 압축 방식, 쿼리 구문, 그리고 서비스 경계에 묶어두는 것이며, 이 네 가지 모두 나중에 되돌리려면 엄청난 고통이 따릅니다.

일반적인 생성 명령문에는 12가지 정도의 중요한 매개변수가 포함됩니다. 벡터 차원은 임베딩 모델과 정확히 일치해야 합니다. 유사도 측정 기준(코사인, 내적, 유클리드 거리)은 해당 모델이 훈련된 방식과 일치해야 합니다. IVF 클러스터 수는 공간이 얼마나 세밀하게 분할될지를 결정합니다. 양자화 설정은 각 벡터가 얼마나 강력하게 압축될지를 결정하는데, SQ8은 높은 리콜률을 유지하면서 메모리를 약 75%만큼 줄이는 반면, SQ4는 실제 정확도 손실을 감수하고 메모리를 더 많이 줄입니다. 훈련 샘플 크기는 클러스터 중심점이 얼마나 대표성을 가질지를 결정합니다. 이 모든 요소는 인덱스가 처리하게 될 모든 쿼리의 리콜, 지연 시간 및 비용에 영향을 미치는 조절 수단입니다.

설정으로 해결할 수 없는 상충 관계

당신이 무엇을 만들든, 그것은 삼면의 긴장 관계 속 어딘가에 안착하게 됩니다. 이 세 가지 모퉁이 중 한 번에 두 곳은 선호할 수 있지만, 세 곳 모두를 한 번에 만족시킬 수는 없습니다.

재현율을 높이려고 하면 더 많은 클러스터를 검색하고, 더 많은 후보를 평가하며, 재순위화 패스를 추가하기 때문에 지연 시간이 길어지고 비용도 함께 상승합니다. 지연 시간을 줄이려고 하면 더 적은 클러스터를 검색하고 더 강력하게 압축하기 때문에 재현율이 떨어집니다. 인프라 비용을 줄이려고 하면 인덱스를 디스크에 올리거나 양자화를 더 많이 적용하게 되는데, 이는 앞선 두 가지 요인과 상충 관계에 있습니다. 이 세 가지 모두에서 우위를 차지하는 설정은 존재하지 않습니다. 인덱스 유형과 생성 시점에 선택한 매개변수에 따라 이 상충 관계의 공간 중 어느 구원에 도달할 수 있는지가 결정되며, 이후에 아무리 튜닝을 하더라도 그 한계를 넘어설 수는 없습니다.

세 개의 지수, 세 가지 다른 베팅

카우치베이스는 여러 가지 벡터 인덱스 전략을 제공하며, 이들은 쉽게 상호 교환할 수 없습니다. 각 전략은 데이터가 어디에 위치하고 쿼리가 어떻게 흘러가는지에 대해 서로 다른 구조적 선택을 하며, 이 선택은 인덱스를 생성하는 순간 고정됩니다.

하이퍼스케일 벡터 인덱스는 10억 개 규모의 벡터 범위를 위해 구축됩니다. 이는 라우팅과 검색을 분리합니다. 클러스터 중심점의 작은 그래프가 RAM에 유지되면서 각 쿼리를 관련된 소수의 클러스터로 라우팅하고, 실제 벡터는 디스크 친화적인 Vamana 그래프 형태의 SSD에 저장됩니다. 이것이 중요한 이유는 단순한 산술에 있습니다. 768차원의 벡터 10억 개는 약 3TB의 원시 부동소수점 데이터이며, 상식적인 서버라면 이를 메모리에 보관할 수 없습니다. 라우팅 레이어만 상주하도록 유지함으로써, 이 인덱스는 적은 양의 RAM으로 거대한 말뭉치를 처리하고 데이터가 증가해도 지연 시간을 안정적으로 유지합니다.

컴포지트 벡터 인덱스는 반대 방향의 선택을 합니다. 바로 '필터 먼저'라는 방식입니다. 이는 IVF 클러스터링을 사용하여 스칼라 필드와 함께 벡터 컬럼을 담고 있는 글로벌 보조 인덱스입니다. 쿼리에 테넌트나 카테고리 같은 스칼라 필드 제약 조건이 있는 경우, 이러한 필터들은 벡터 검색이 실행되기 전에 적용됩니다. 필터가 충분히 좁아서 전체 데이터의 아주 작은 부분만 남기게 되면, 비용이 많이 드는 가장 인접한 이웃(nearest-neighbor) 작업은 전체 데이터셋 대신 그 일부분에 대해서만 실행됩니다. 이것은 멀티 테넌트 애플리케이션과 강력하게 파티셔닝된 카탈로그를 위한 올바른 도구입니다. 문제점은 메모리 압박입니다. 낮은 지연 시간을 달성하려면 작업 세트가 인덱스 서비스의 메모리 할당량 내에 상주해야 하며, 인덱서가 해당 할당량을 초과하게 되면 메모리가 해제될 때까지 스캔 제공을 중단합니다. 1536차원의 벡터 1억 개가 있는 경우, 중심점(centroid), 그래프 구조, 스칼라 컬럼을 제외하고 양자화된 벡터 페이로드(SQ8, 차원당 1바이트)만 해도 대략 144 GB에 달합니다.

FTS 검색 벡터 인덱스는 전문 검색(Full-Text Search) 서비스 내에 존재하며, 단일 쿼리 내에서 키워드 관련성과 벡터 유사성을 결합하는 유일한 인덱스입니다. 제품에 의미론적 검색과 더불어 퍼지 매칭, 형태소 분석(stemming), 자동완성 기능이 필요한 경우 이것이 가장 적합하며 운영하기 가장 단순합니다. 실질적인 한계는 약 1억 개의 벡터 부근에 위치하며, 이 범위를 넘어가면 메모리 맵(memory-mapped) 저장소에 부하가 걸리기 시작합니다.

잘못된 선택이 사건으로 이어지는 곳

위험은 하나의 인덱스는 좋고 다른 인덱스는 나쁘다는 데 있지 않습니다. 실패 양상이 조용히 나타나며, 잘못된 설계 결정에 대한 대가는 대개 훨씬 뒤에 나타난다는 점입니다. 몇 가지 패턴이 반복해서 나타납니다.

여기에 단순함의 함정이 있습니다. 팀은 가장 쉽게 구축할 수 있다는 이유로 FTS(전체 텍스트 검색)를 선택합니다. 2천만 개의 벡터에서는 훌륭하게 작동합니다. 130밀리언(1억 3천만) 개가 되면 메모리 압박과 조용히 사투를 벌이게 되며, 이를 벗어난다는 것은 서비스 경계를 넘나들며 모든 쿼리를 FTS 검색 구문에서 인덱스 서비스 구문으로 다시 작성해야 함을 의미합니다. 생성 시점의 쉬운 선택이 나중에는 비용이 많이 드는 마이그레이션이 됩니다.

‘규모 집착의 함정’이 있습니다. 어떤 팀은 10억 규모를 목표로 ‘하이퍼스케일 인덱스’를 선택했지만, 실제 트래픽의 95%는 테넌트 필터링을 거칩니다. 이들은 ‘필터 우선’ 방식이 주는 이점을 활용하지 못한 채, RAM에 있는 데이터의 0.1%도 채 되지 않는 양으로 처리할 수 있었던 검색 작업에 SSD의 지연 시간을 감수하고 있는 셈입니다.

그리고 거의 아무도 예상하지 못하는 코드북 드리프트(codebook drift)가 있습니다. 모든 IVF 기반 인덱스는 빌드 시점에 가져온 데이터 샘플을 기반으로 클러스터 중심점(centroid)을 학습합니다. 새로운 데이터가 유입되고 원래 샘플에서 멀어질(드리프트)수록, 중심점들은 더 이상 대표성을 갖지 못하게 되고 재현율(recall)은 서서히 떨어집니다. 오류는 발생하지 않습니다. 경고도 울리지 않습니다. 결과는 그저 점차 나빠질 뿐입니다. 해결책은 주기적인 재구축이며, 위험이 존재한다는 사실을 알면 아주 간단하지만, 대부분의 팀은 이미 피해를 입고 나서야 이를 깨닫습니다.

이러한 이유들로 인해 생성 시점에서의 결정은 프로젝트 막바지에 체크박스 하나를 켜고 끄는 것처럼 단순할 수 없습니다. 올바른 색인은 현재의 규모, 필터 선택도, 키워드 요구사항, 기존 인프라, 그리고 예상 성장이 한꺼번에 작용하는 함수의 결과물이며, 단 하나의 신호만으로 결정될 수 없습니다. 그 논리는 일련의 짧은 질문들을 거치며, 그 질문들이 던져지는 순서가 중요합니다.

첫 번째 질문은 워크로드에 의미론적 검색과 함께 실제 키워드 검색이 필요한지 여부를 다룹니다. 필요하고 코퍼스가 1억 개 미만의 벡터로 구성된 경우, FTS 인덱스가 한곳에서 둘 다 커버합니다. 코퍼스가 그 한도를 초과하면, 벡터 쪽을 위한 Hyperscale 인덱스와 키워드 쪽을 위한 별도의 FTS 인덱스를 쌍으로 묶는 하이브리드 설정으로 답이 바뀝니다.

키워드 검색이 그림에 없으면 규모가 다음 단계입니다. 1억 개 미만의 벡터에서는 대부분의 옵션이 열려 있습니다. 1억 개를 넘어가면 FTS 색인은 메모리 문제로 제외되며 경쟁은 컴포지트 및 하이퍼스케일 색인으로 좁혀집니다.

필터 선택도가 보통 그 우열을 가립니다. 쿼리에 코퍼스의 아주 좁은 일부분만 남기는 엄격한 스칼라 필터가 포함된 경우, 복합(Composite) 인덱스와 필터 우선 실행 방식이 유리합니다. 필터가 광범위하거나 없는 경우에는 복합 인덱스가 전혀 사용되지 않을 스칼라 계층의 비용을 치르게 되므로 하이퍼스케일(Hyperscale) 인덱스가 더 나은 선택입니다.

성장은 전체 시스템의 기반이 됩니다. 현재 20M이고 로드맵상 150M에 달하는 데이터셋은 단순한 현재의 데이터 형태가 아니라, 그러한 마이그레이션 경로를 이미 염두에 두고 구축되어야 합니다. 이러한 각 질문은 실력 있는 엔지니어라도 그럴듯한 잘못된 방향으로 빠질 수 있는 지점을 나타내며, 답변들은 서로 상호작용합니다. 전체 그림에는 사용 가능한 RAM, 2단계 LLM 리랭킹 패스의 비용, 그리고 인덱스 유형 간의 마이그레이션 마찰과 같은 훨씬 더 많은 요소가 포함됩니다.

올바른 답은 올바른 질문에서 시작됩니다.

좋은 추천이 이루어지는 방식에는 일정한 패턴이 있습니다. 고객과 함께 앉아 있는 솔루션 엔지니어는 인덱스에 대한 이야물로 시작하지 않습니다. 그들은 질문을 던지는 것으로 시작하며, 그 질문들은 의도적인 순서로 배열되어 있습니다. 컨설팅 맥락 없이 이루어진 인덱스 추천은 전문 지식으로 포장된 추측에 불과하기 때문에, 설정을 다루기 전에 유스케이스를 먼저 이해해야 합니다.

이 사용 사례에는 명확히 밝혀야 할 여러 계층이 있습니다. 애플리케이션은 검색된 결과를 실제로 어떻게 활용하고 있을까요? LLM에 데이터를 공급하는 RAG 파이프라인은 실시간 상품 추천 위젯과는 다른 리콜 특성이 필요합니다. 이론적으로만이 아니라 실제로 데이터는 어떻게 분할되고 있을까요? 어떤 팀은 자신의 워크로드를 “다중 테넌트(multi-tenant)”라고 설명할 수 있겠지만, 만약 한 테넌트가 벡터 80%를 보유하고 있다면, 필터 선택성 계산은 균일한 경우와는 완전히 다르게 나타납니다. 현재의 규모가 실제 수치인가, 아니면 실제로 증가하고 있는 규모를 대략적으로 추정한 것일까요? 이 대답은 중요합니다. 왜냐하면 오늘날의 3,000만 개 벡터에 적합한 인덱스와 내년의 2억 개 벡터에 적합한 인덱스는 때때로 서로 다른 개체일 수 있으며, 이 둘 간의 마이그레이션에는 비용이 발생하므로 이를 지금 설계 결정에 반영해야 하기 때문입니다.

그리고 종종 가장 간과되는 인프라 문제가 있습니다. 클러스터가 이미 다른 워크로드를 위해 인덱스 서비스(Index Service)를 실행하고 있습니까? 프로비저닝된 전문 검색(Full-Text Search) 서비스가 있습니까? 기술적으로 우수한 인덱스 선택은 아직 존재하지 않는 서비스를 구축하고, 노드를 추가하며, 운영 팀을 재교육해야 하는 경우 실무적으로는 잘못된 선택일 수 있습니다. 이미 배포된 서비스 내에서 실행되는 약간 덜 최적화된 인덱스가 이론적인 승자보다 몇 달 앞서 더 나은 성능을 발휘할 수 있습니다.

올바른 질문을 던질 줄 알기만 하면 이 중 복잡한 것은 없습니다. 어려움은 CREATE 문이 실행되기 전에 이러한 질문들이 체계적으로 함께 던져지는 경우가 드물다는 점입니다. 엔지니어들은 가장 눈에 띄는 신호—대개 규모나 그들이 읽은 최신 기술—에 집착하고 거기서부터 바깥쪽으로 작업을 진행하는 경향이 있습니다. 그러한 집착이 바로 불일치가 시작되는 지점입니다.

올바른 질문을 던지도록 만들어진 어드바이저

벡터 인덱스 어드바이저는 추천의 품질이 전적으로 그 결정을 내리기 전에 수집된 정보의 품질에 달려 있다는 관찰을 바탕으로 구축되었습니다. 에이전트는 답변으로 시작하지 않습니다. 대화로 시작하여, 솔루션 엔지니어가 사용하는 것과 동일한 진단 순서(규모, 필터 패턴, 키워드 요구사항, 기존 서비스, 예상 성장세에 대해 묻고, 각 답변을 고정하기 위한 구체적인 선택지를 제시하는 방식)를 거쳐 나갑니다.

구체적인 선택지의 근거가 중요한 이유입니다. “필터가 얼마나 엄격합니까?”와 같은 질문에는 대부분의 사람들이 모호한 답변을 내놓을 것입니다. 반면 “코퍼스의 5% 미만, 5~20%, 20% 초과, 또는 필터 없음”과 같은 구체적인 선택지를 제시하는 질문에는 명확한 답변을 얻을 수 있습니다. 이러한 구체성이야말로 후속 추론의 신뢰성을 보장합니다. 각 답변은 측정 가능한 방식으로 의사결정 공간을 좁혀주며, 에이전트는 확인된 사항, 아직 미해결인 사항, 그리고 현재 알고 있는 정보로부터 이미 도출 가능한 함의를 추적합니다.

대화 하단에서, 에이전트는 모델의 추정에 의존하는 대신 실제 데이터를 기반으로 결정론적 검증을 실행합니다. 권장 사항은 유사한 상황이 다르게 해결된 사례를 식별하기 위해 실제 워크로드 라이브러리와 비교됩니다. 실제 Couchbase 테스트 실행의 벤치마크 데이터는 튜닝 지침을 제공하여 제시된 수치가 어림짐작이 아닌 측정된 성능을 기반으로 하도록 합니다.

전체 추론 과정이 인터페이스에 단계별로 표시되며, 이는 단순한 디버깅 도구 그 이상입니다. 이는 추천 결과에 그 이유가 함께 제공되어, 이를 읽는 사람이 논리를 따라가거나, 전제를 반박하거나, 답변을 수정할 수 있음을 의미합니다. 질문할 수 있는 추천은 단순히 도달하는 추천보다 더 큰 신뢰를 구축합니다.

요점

벡터 검색에는 착각을 불러일으키는 곡선이 존재합니다. 뭔가 작동하게 만드는 것은 순식간입니다. 규모에 맞게 제대로 작동하게 만드는 것은 그 자체로 하나의 전문 분야이며, 시작할 때 생성한 인덱스는 누군가 매개변수를 조정하기도 훨씬 전에 재현율, 지연 시간, 비용, 그리고 마이그레이션의 고통에 대한 한계를 설정합니다. 장애 보고서를 통해 추적해보면 가장 큰 비용이 드는 놀라운 일들은 모두 같은 지점에서 비롯됩니다. 그것은 바로 지원하도록 설계된 워크로드에 대한 전체적인 그림 없이 생성 시점에 내린 결정입니다. 인덱스 생성을 실제로 아키텍처적 결정으로 대하고, 설정을 작성하기 전에 실제 유스케이스를 드러내는 질문들을 던진다면, 그러한 놀라운 일들의 대부분은 결코 일어나지 않을 것입니다.

이 기사 공유하기

작가

댓글 남기기

카우치베이스 카펠라를 시작할 준비가 되셨나요?

개발 시작하기

NoSQL을 탐색하고, 리소스를 찾아보고, 튜토리얼을 시작하려면 개발자 포털을 확인하세요.

카펠라 프리 사용하기

단 몇 번의 클릭으로 카우치베이스(Couchbase)를 직접 체험해 보세요. Capella DBaaS는 시작하기 가장 쉽고 빠른 방법입니다.

연락해

Couchbase 제품군에 대해 더 알고 싶으신가요? 저희가 도와드리겠습니다.