롱테일(Long-Tail) 및 결과 없음(Zero-Result) 쿼리 처리하기
요약
검색 시스템에서 빈도가 낮은 롱테일(Long-Tail) 쿼리와 결과 없음(Zero-Result) 문제를 분석합니다. 지프 법칙을 통해 쿼리 분포의 특성을 설명하고, 테일 영역의 문제를 해결하기 위한 의미론적 검색(Semantic Retrieval)의 필요성과 비즈니스 가치 산출법을 제시합니다.
핵심 포인트
- 쿼리 빈도는 지프 법칙을 따르며, 상위 0.1%가 전체 볼륨의 절반을 차지함
- 수동 큐레이션과 클릭 기반 학습은 롱테일 쿼리 대응에 한계가 있음
- 테일 영역은 어휘 매칭 대신 의미론적 검색(Semantic Retrieval)이 필수적임
- 제로 결과율을 일일 위험 매출(Revenue at Risk)로 변환하여 비즈니스 가치 증명 가능
헤드(Head) 쿼리는 대시보드에 가시적으로 나타나기 때문에 모든 관심을 받습니다. 하지만 실패가 발생하는 곳은 테일(Tail)이며, 그 이유는 쿼리 자체의 문제라기보다 분포에 관한 산술적인 문제입니다.
분포의 형태
쿼리 빈도는 헤비 테일(Heavy-tailed) 분포를 따릅니다. 표준 모델은 지프(Zipf) 법칙입니다. 즉, $r$번째로 흔한 쿼리의 빈도는 어떤 지수 $s$에 대해 $1 / r^s$에 비례합니다. 계산을 깔끔하게 하고 고전적인 사례인 $s = 1$을 가정하면, 순위 $R$까지의 누적 볼륨은 조화 합(Harmonic sum)이 됩니다:
H_R = r = 1..R 에 대한 1/r 의 합 ~= ln(R) + 0.5772
D개의 고유한 쿼리 중 상위 R의 볼륨 점유율 = H_R / H_D
백만 개의 고유한 쿼리가 있을 때, 상위 천 개가 차지하는 볼륨은 얼마나 될까요?
H_1000 = ln(1000) + 0.5772 = 6.9078 + 0.5772 = 7.4850
H_1,000,000 = ln(1,000,000) + 0.5772 = 13.8155 + 0.5772 = 14.3927
...
고유 쿼리의 상위 0.1%가 전체 볼륨의 약 절반을 차지합니다. 나머지 절반은 999,000개의 쿼리에 분산되어 있으며, 이 중 대부분은 아주 소수의 횟수만 발생합니다. 그리고 실제 쿼리 로그는 보통 $s$가 1보다 낮은 경우가 많으며, 이는 테일을 더욱 무겁게 만듭니다. 즉, 헤드의 점유율은 떨어지고 분산은 더 넓어집니다.
여기서 세 가지 결과가 직접적으로 도출됩니다. 첫째, 수동 큐레이션(Manual curation)은 헤드를 커버할 수는 있지만 테일에는 손을 댈 수 없습니다. 테일에는 큐레이션할 만큼 반복되는 쿼리가 없기 때문입니다. 둘째, 클릭(Clicks)을 통해 학습되는 모든 정보는 테일에서 결핍됩니다. 각 쿼리에 클릭이 거의 발생하지 않기 때문입니다. 셋째, 모든 트래픽에 대해 평균을 낸 결과 없음(Zero-result) 비율은 헤드에 의해 지배됩니다. 하지만 헤드는 바로 문제가 발생하지 않는 지점입니다. 따라서 대시보드의 수치는 매우 훌륭해 보일 수 있지만, 실제로는 테일에서 심각한 실패가 발생하고 있을 수 있습니다.
아키텍처를 결정짓는 필연적인 결과는 다음과 같습니다. 테일(tail)은 어휘 매칭(lexical matching)이 어휘적 중첩(vocabulary overlap)을 잃어버리는 지점이며, 의미론적 검색(semantic retrieval)이 그 비용을 정당화하는 지점입니다. 이것이 semantic versus keyword search에서 다루는 전형적인 분석이며, 테일 대 헤드(tail-vs-head) 분할이 검색 평가(retrieval evaluation)를 세분화하는 올바른 방법인 이유입니다.
제로 결과율(Zero-result rate)의 가치
제로 결과율은 하나의 비율일 뿐이며, 비율만으로는 엔지니어에게 예산을 확보해 줄 수 없습니다. 이를 변환하십시오. 다음 네 가지 입력값은 모두 당신의 것입니다:
일일 위험 매출 (revenue at risk per day) = S * z * c * v
S 일일 검색 수 (searches per day)
...
입력 예시 -- 네 가지 모두 교체하십시오
S = 200,000 z = 0.06 c = 0.03 v = $40
...
이 수치를 정확하게 읽어야 합니다. 이것은 예측(forecast)이 아니라 상한선(upper bound)입니다. 이 수치는 복구된 모든 검색이 일반 검색과 동일한 전환율을 기록할 것이라고 가정하며, 이는 낙관적인 수치입니다. 아무것도 찾지 못한 쿼리는 실제로 당신이 재고를 보유하지 않은 제품에 대한 것일 수도 있기 때문입니다. 방어 가능한 수치를 원한다면 이 값을 절반으로 줄이십시오. 절반으로 줄이더라도, 이는 일반적으로 검색 팀의 구성원이 슬라이드에 제시할 수 있는 가장 큰 단일 숫자이며, 비즈니스에서 이미 추적하고 있는 네 가지 숫자로부터 완전히 도출됩니다.
완화 계단 (The relaxation ladder)
복구(Recovery)는 순서대로 시도되는 폴백 체인(fallback chain)이며, 충분한 결과를 생성하는 첫 번째 단계에서 멈춥니다. 각 단계는 리터럴 쿼리(literal query)의 요소를 조금씩 더 포기합니다.
- 철자 및 레이아웃 (Spelling and layout). 쿼리 이해 (query understanding)에서 다루는 노이즈 채널 교정 (noisy-channel correction)과 더불어, 사용자가 두 개 이상의 스크립트(script)를 사용하는 경우 키보드 레이아웃 음차 (keyboard-layout transliteration)를 적용합니다. 가장 비용이 적게 드는 단계이며, 종종 가장 큰 단일 복구 효과를 제공합니다.
- 유의어 및 어간 추출 (Synonyms and stemming). 재구성 쌍 (reformulation pairs)을 살펴봄으로써 자체 로그에서 추출합니다. 누군가가 실패한 쿼리 다음에 입력한 쿼리는 레이블이 지정된 유의어 후보이며, 이는 사용자 자신의 어휘를 반영하므로 유의어 사전 (thesaurus)보다 더 나은 소스입니다.
- 불리언(Boolean) 완화. 5개 용어에 대한 엄격한 AND 연산은 그중 하나만 실패해도 실패합니다. 최소 일치 (minimum-should-match) 규칙으로 전환하여, 예를 들어 용어의 70%를 요구하도록 설정하십시오. 그리고 IDF(역문서 빈도)가 오름차순인 순서대로 용어를 제거하여, 정보량이 가장 적은 단어가 먼저 제거되도록 합니다. 필요한 IDF 값은 이미 인덱스에 있으며, 산술 연산은 관련성 튜닝 (relevance tuning)에서 이루어집니다.
- 의미론적 폴백 (Semantic fallback). 쿼리를 임베딩 (embed)하고 유사도에 따라 검색합니다. 이는 사용자의 단어가 어떤 문서에도 나타나지 않는 경우를 처리하며, 이는 롱테일 실패의 주된 원인이자 어휘적 완화(lexical relaxation)만으로는 도달할 수 없는 영역입니다.
- 카테고리 또는 의도 폴백 (Category or intent fallback). 파싱 (parse)을 통해 카테고리가 추출되었다면, 해당 카테고리를 인기순으로 보여줍니다. 이는 사용자가 요청한 정확한 결과는 아니지만, 그 사실을 정직하게 보여주는 방식입니다.
- 기능을 수행하는 빈 상태 (An empty state that does work). 파싱된 내용을 보여주고, 각 제약 조건을 제거 가능한 형태로 제공하며, 알림을 제안합니다. 무엇을 찾으려 했는지 설명해 주는 빈 페이지는 복구 가능한 상황이지만, 아무것도 없는 빈 페이지는 이탈을 초래합니다.
모든 쿼리에 대해 어떤 단계(rung)가 작동했는지 로그를 남기십시오. 그 로그는 시스템 전체에서 가장 가치 있는 진단 도구입니다. 단계별 빈도는 문제가 철자인지, 어휘인지, 불리언의 엄격함인지, 아니면 실제 카탈로그의 공백인지를 직접적으로 가리키며, 각각의 문제는 담당자가 다릅니다.
제로(Zero)보다 더 나쁜 실패
결과 없음(Zero-result) 페이지는 최소한 탐지라도 가능합니다. 더 흔하면서도 더 치명적인 실패는 20개의 결과를 반환하지만, 그중 사용자가 원하는 것이 단 하나도 없는 쿼리입니다. 이러한 현상은 구조적으로 '결과 없음(Zero-result)' 대시보드에는 포착되지 않으며, 사용자가 검색 기능이 고장 났다고 생각하기보다 당신에게 해당 제품이 없다고 결론짓게 만들기 때문에 훨씬 더 해롭습니다.
결과 수(result count)가 아닌 결과의 양상(outcome)을 설명하는 신호들을 통해 이를 탐지하십시오:
- 클릭 없음 비율 (No-click rate): 결과가 한 페이지 가득 차 있음에도 불구하고 그중 어떤 것도 클릭하지 않는 쿼리입니다. 쿼리 빈도 대역(query frequency band)별로 세분화하십시오. 롱테일(tail) 영역이 더 나쁠 것이며, 그것이 바로 핵심입니다.
- 재질의 비율 (Reformulation rate): 몇 초 이내에 발생하는 두 번째 쿼리는 사용자가 첫 번째 쿼리가 실패했음을 자신만의 언어로 당신에게 말하고 있는 것입니다. 재질 쌍(Reformulation pairs)은 최고의 실패 신호인 동시에 당신이 가질 수 있는 최고의 유의어(synonym) 소스이기도 합니다.
- 포고스틱킹 (Pogo-sticking): 클릭 후 몇 초 이내에 돌아왔다가 다시 클릭하는 행위입니다. 결과가 적절해 보였으나 실제로는 그렇지 않았음을 의미하며, 이는 대개 스니펫(snippet)이 문서가 보증하지 못하는 내용을 약속하고 있음을 뜻합니다.
- 깊은 페이지네이션 (Deep pagination): 4페이지에 있는 사용자는, 설령 k = 10에서 계산된 모든 지표가 그렇지 않다고 말할지라도 당신의 랭킹(ranking)이 실패했음을 보여주는 사용자입니다.
이 네 가지 모두 위치 편향(position-biased)되어 있으며, 그 자체로 관련성 지표(relevance metric)는 아닙니다. 이에 대한 교정 방법은 지표 페이지에 나와 있습니다. 우선순위 분류(triage) 단계에서는 교정되지 않은 상태로 사용해도 괜찮습니다. 왜냐하면 당신은 수준을 측정하는 것이 아니라 이상치(outliers)를 찾고 있는 것이기 때문입니다.
이 신호들을 사용하는 실질적인 방법은 롱테일을 개별적으로 조사하는 것이 아니라 집계(aggregate)하는 것입니다. 개별 롱테일 쿼리는 하나씩 대응하기에는 너무 드물게 발생하므로, 추출된 카테고리, 임베딩(embedding), 또는 트리거된 단계(rung of the ladder)별로 클러스터링(cluster)하십시오. 그런 다음 클러스터를 '총 볼륨 × 실패율'로 순위를 매기십시오. 동일한 누락된 유의어 때문에 모두 실패하는 2,000개의 서로 다른 쿼리 클러스터는 단 한 번의 오후 작업으로 해결할 수 있는 문제이지만, 쿼리별 보기(per-query view)에서는 보이지 않습니다. 이러한 집계 단계야말로 롱테일을 '수정 불가능한 통계적 사실'에서 '해결해야 할 백로그(backlog)'로 바꾸어 놓는 과정입니다.
관련 자료
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기