디스커버리 검색: 검색에도 맥락이 필요해요
디스커버리 검색: 검색에도 맥락이 필요해요 (Discovery needs context)
크리스토퍼 콜럼버스와 그의 선원들은 대서양을 건너 항해할 때 미국 대륙을 찾고 있던 게 아니었어요. 그들은 지구가 둥글다고 믿었기에 인도로 가는 새로운 항로를 찾고 있었죠. 새로운 대륙에 대해서는 전혀 몰랐지만, 서쪽으로 나아가다 보니 우연히 그 대륙을 발견하게 됐어요.
그들은 지리가 허락하지 않아서 자신들의 _목표(target)_에 도달할 수 없었어요. 하지만 인도가 아니라는 걸 깨닫자, 그들은 왕국을 위해 그곳을 새로운 "발견(discovery)"이라고 주장했어요. 선원들이 항해하려면 물이 필요하다고 생각해 보면, 우리는 물에서는 _맥락(context)_이 긍정적이고 육지에서는 부정적인 맥락을 세울 수 있어요. 선원의 항해가 육지에 막히자 더 나아갈 수 없게 됐고, 새로운 항로가 발견된 거예요. Qdrant의 새 기능인 **디스커버리 검색(Discovery search)**을 살펴보면서 이 _목표(target)_와 _맥락(context)_이라는 개념을 머릿속에 담아 두기로 해요.
출처: 공식문서
디스커버리 검색이 뭔가요?
1.7 버전에서 Qdrant는 이 새로운 API를 공개했어요. 이 API는 순수한 벡터만으로 검색이 수행되는 공간을 제약할 수 있게 해 줘요. 벡터 공간을 더 통제된 방식으로 탐색할 수 있게 해 주는 강력한 도구예요. 목표에 반드시 가장 가깝지 않아도, 그럼에도 검색에 관련된 포인트를 찾는 데 사용할 수 있어요.
페이로드 필터를 사용해서 검색에 사용 가능한 포인트를 이미 선택할 수 있어요. 이것 자체만으로도 매우 다재다능하죠. 복잡한 필터를 만들어서 조건을 충족하는 포인트만 결정적으로 보여주게 할 수 있으니까요. 하지만 각 포인트와 연결된 페이로드는 임의적이라서 벡터 공간에서의 위치에 대해선 아무것도 알려주지 못해요. 다시 말해, 관련 없는 포인트를 걸러내는 것은 하이퍼플레인(hyperplane, 양성/음성 벡터 사이를 자르는 평면)을 만드는 것보다는 _마스크(mask)_를 만드는 것에 가까워요.
맥락(context) 이해하기
여기서 **벡터 맥락(vector context)**이 도움이 돼요. 우리는 _맥락_을 쌍(pair)들의 리스트로 정의해요. 각 쌍은 양성(positive) 벡터와 음성(negative) 벡터로 이뤄져 있어요. 맥락이 있으면 벡터 공간 내에 하이퍼플레인을 정의할 수 있는데, 이 평면은 항상 음성 벡터보다 양성 벡터를 선호해요. 이는 효과적으로 검색이 수행되는 공간을 분할해요. 공간을 분할한 다음에는, 그 공간과 더 유사한 포인트를 반환하기 위해 _목표(target)_가 필요해요.
양성/음성 벡터는 추천 인터페이스(recommendation interface)를 쓰라는 것처럼 보일 수 있지만, _맥락_의 경우에는 양성-음성 방식으로 짝을 이뤄야 해요. 이것은 머신러닝의 트리플렛 로스(triplet loss) 개념에서 영감을 받은 거예요. 트리플렛 로스는 anchor, positive, negative라는 세 벡터를 다루죠. 트리플렛 로스는 anchor가 negative 벡터보다 positive 벡터에 얼마나 더 가까운지를 평가해서, positive/negative 포인트를 "이동"시켜 더 나은 평가를 얻는 방식으로 학습이 이뤄져요. 하지만 디스커버리에서는 positive/negative 벡터를 고정된 포인트로 간주하고, 이 특성을 더 잘 맞추는 "앵커(anchor)" 또는 결과 후보를 전체 데이터셋에서 검색해요.
따라서 **디스커버리 검색**은 두 가지 주요 입력으로 구성돼요:
- target: 관심의 핵심 포인트
- context: 방금 정의한 양성/음성 포인트의 쌍
하지만 이게 유일한 사용법은 아니에요. 대신 맥락만 제공해서 컨텍스트 검색(Context Search)을 호출할 수도 있어요. 이 방식은 맥락이 정의한 공간을 탐색하고 싶은데 특정 목표가 없을 때 유용해요. 잠깐, 이건 나중에 ↪ 자세히 다룰게요.
실전 디스커버리 검색 사례
먼저 목표와 맥락을 함께 쓰는 첫 번째 사례부터 이야기해 볼게요.
이것이 왜 유용한지 이해하려면 실생활 예시를 보는 게 좋아요: CLIP 같은 멀티모달 인코더로 텍스트 그리고 이미지로부터 이미지를 검색하는 경우예요. CLIP은 이미지와 텍스트를 같은 벡터 공간에 임베딩할 수 있는 신경망이에요. 즉 텍스트 쿼리나 이미지 쿼리 중 무엇으로든 이미지를 검색할 수 있다는 뜻이에요. 이 예제에서는 음식 추천 데모를 재사용해서 텍스트 입력에 "burger"를 입력할게요.
이건 기본적으로 최근접 이웃 검색이에요. 기술적으로 우리는 버거 이미지들만 있는데, 그중 하나는 버거의 로고 표현이에요. 하지만 우리가 원하는 건 실제 버거예요. 이 로고 이미지를 음성 예제로 추가해서 제외해 볼게요.
잠깐, 방금 무슨 일이 일어난 거예요? 이 사진들은 버거와 전혀 관련이 없는데도 첫 번째 결과에 나타나고 있어요. 데모가 고장 난 건가요?
알고 보니 멀티모달 인코더는 예상과 다르게 동작할 수 있어요. 이미지와 텍스트는 같은 공간에 임베딩되지만, 반드시 서로 가까이 있는 건 아니에요. 즉 이 분포를 이미지용 평면과 텍스트용 평면, 두 개의 분리된 평면으로 상상해 볼 수 있어요.
이때 바로 디스커버리가 빛을 발해요. 디스커버리는 다른 모드(텍스트)의 목표를 사용하면서도 같은 모드(이미지)를 고려해 공간을 제약할 수 있게 해 주거든요.
디스커버리 검색은 또한 더 많은 컨텍스트 쌍의 형태로 검색 엔진에 피드백을 계속 줄 수 있게 해 줘서, 원하는 것을 찾을 때까지 검색을 계속 다듬을 수 있어요.
또 하나 직관적인 예를 들어 볼게요. 생선 피자를 찾고 있는데 피자 이름이 헷갈린다고 가정해 봐요. 그냥 "pizza"라고 입력하고, 고기보다 생선을 선호한다고 지정할 수 있어요. 디스커버리 검색은 이런 입력을 사용해서 생선 피자를 제안해 줘요... 설령 그 이름이 생선 피자가 아니라 해도 말이죠!
컨텍스트 검색 (Context search)
이번에는 두 번째 사례, 맥락만 제공하는 경우예요.
좋아하는 음악 스트리밍 서비스에서 계속 같은 추천에 갇혀 본 적 있나요? 이는 유사성 버블(similarity bubble)에 갇혀 있기 때문일 수 있어요. 사용자 입력이 복잡해질수록 다양성은 줄어들고, 시스템이 다른 걸 추천하도록 강제하기가 더 어려워져요.
컨텍스트 검색은 단일 포인트 주위로 검색을 집중하지 않음으로써 이 문제를 해결해요. 대신 벡터 공간의 특정 구역 내에서 포인트를 무작위로 선택해요. 이 검색은 _트리플렛 로스_의 영향을 가장 많이 받아요. 점수가 _"포인트가 positive 벡터보다 negative 벡터에 얼마나 더 가까운가?"_로 생각될 수 있기 때문이에요. positive 쪽에 더 가까우면 그 점수는 0이 돼요. 같은 구역 내의 다른 포인트와 마찬가지죠. 하지만 negative 쪽에 있으면 멀어질수록 점점 더 큰 음수 점수가 할당돼요.
고차원 공간에서 복잡한 취향을 만드는 건 더 쉬워져요. 그냥 검색에 컨텍스트 쌍을 더 추가하면 되니까요. 이렇게 하면 입력의 컨텍스트만으로 만들어진 검색별 "카테고리"에서 포인트를 선택할 수 있을 만큼 공간을 충분히 제약할 수 있어요.
이렇게 하면 양성/음성 피드백을 제공하거나, 쌍의 다른 순열을 시도하면서, 통제력을 유지하면서도 새로움을 주는 추천을 받을 수 있어요.
핵심 요약
- 디스커버리 검색은 벡터 공간에서 통제된 탐색을 위한 강력한 도구예요.
- 양성/음성 벡터로 구성된 컨텍스트는 검색 공간을 제약하고, 목표(target)는 검색을 안내해요.
- 실전 사례로는 멀티모달 검색, 다양한 추천, 컨텍스트 기반 탐색이 있어요.
- 이것의 배후 수학과 사용법을 더 배울 준비가 됐나요? 문서를 확인해 보세요.