밀집 검색의 허브 문제를 2010년 거리 집중 이론으로 진단하고, 교차언어 임베딩의 보정을 이식하다
직관적인 대안 세 가지를 먼저 시도해 측정으로 전부 기각한 뒤, 다른 분야에서 해법을 가져와 추가 API 비용 없이 검색 정확도를 올렸습니다. 규모를 300배로 늘려 다시 측정했을 때 드러난 손실과 그 수리까지 함께 적었습니다.
- 밀집 시딩 recall@10 — 같은 조건의 키워드 검색은 85.2
- 77.5 → 97.0
- 추가 API 비용 · end-to-end 답변 정확도 87% → 97%
- $0
밀집 검색에서 상위 결과가 서로 비슷한 항목으로만 채워지고 정작 정답 문서가 아래로 밀리는 현상이 있었습니다. 50행짜리 밀집 표에서는 임베딩 검색의 recall@10이 17%까지 떨어졌는데, 같은 표에서 단순 어휘 검색은 100%였습니다. 밀집 레그가 어휘 검색보다 못한 구간이 존재한다는 뜻입니다.
흔한 대응은 재순위 모델을 하나 더 붙이는 것입니다. 다만 재순위는 이미 만들어진 상위 후보 목록을 다시 정렬할 뿐이어서, 정답 문서가 그 목록에 들어오지 못한 원인은 그대로 남습니다.
먼저 시도했다가 기각한 것
해법을 찾기 전에 직관적인 대안 세 가지를 먼저 시도했고, 측정 결과로 전부 기각했습니다. 기각 기준은 실험 전에 문서에 적어두고 등록 시점의 커밋 해시를 함께 남겼습니다. 결과를 본 뒤에 기준을 낮추지 않았다는 것을 나중에 확인하기 위해서입니다.
기각된 접근은 재제안 금지 목록에 올라가 있습니다. 같은 오답을 두 번 제안하지 않기 위해서입니다.
진단
증상을 다시 봤습니다. 상위에 몰리는 항목들에는 공통점이 있었습니다. 질의와 특별히 가까워서가 아니라, 여러 질의에 대해 골고루 가까운 벡터들이었습니다.
이는 검색 고유의 문제가 아니라 고차원 공간의 성질입니다. 2010년 JMLR에 실린 거리 집중(distance concentration) 연구가 정확히 이 현상을 다룹니다. 차원이 높아질수록 점들 사이의 거리 분포가 좁아지고, 그 결과 일부 점이 다른 많은 점의 최근접 이웃으로 반복해서 등장하는 허브(hub)가 됩니다. 허브는 질의와 무관하게 상위에 오릅니다.
다른 분야에서 가져온 해법
같은 허브 문제를 이미 오래 다뤄 온 분야가 있습니다. 교차언어 단어 임베딩입니다. 두 언어의 임베딩 공간을 정렬할 때 똑같이 허브 단어가 생기고, 거기서 쓰는 보정 기법이 CSLS(Cross-domain Similarity Local Scaling)입니다. 어떤 점이 이웃들에게 평균적으로 얼마나 가까운지를 빼서, 그 점이 원래 인기가 많아서 가까운 것인지 이 질의에 대해 가까운 것인지를 분리합니다.
이걸 검색 시딩 단계에 이식했습니다. 아래는 6개 케이스를 3회 평균한 단일 문서 결과입니다.
| 조건 | recall@10 |
|---|---|
| 어휘 검색 전용 | 85.2 |
| 밀집 시딩 (이식 전) | 77.5 |
| 밀집 시딩 + CSLS | 97.0 |
수치를 읽는 순서가 중요합니다. 바꾼 것은 밀집 시딩이므로 비교해야 할 두 값은 77.5와 97.0입니다. 그리고 이식 전 밀집 시딩이 어휘 검색보다 낮았다는 사실 자체가 허브 문제의 증상입니다. 이득은 전적으로 밀집 표 케이스에서 나왔습니다(균일 50행 표 22 → 100, 실제 32행 표 50 → 100). 산문 케이스는 이식 전후가 같습니다.
263개 엔티티를 한 워크스페이스로 합쳐 정답이 전체와 경쟁하게 만든 조건에서도 방향은 같습니다(75.8 → 96.0).
| 지표 | 이식 전 | 이식 후 |
|---|---|---|
| 멀티독 recall@10 | 75.8 | 96.0 |
| end-to-end 답변 정확도 (31문항) | 87% | 97% |
추가 API 비용은 발생하지 않았습니다. CSLS는 이미 계산된 임베딩 위의 산술이라 호출이 늘지 않습니다. 재순위 모델을 붙였다면 질의마다 비용이 붙었을 자리입니다.
300배 규모에서 다시 측정한 것
위 결과는 엔티티 약 300개에서 나온 것입니다. 실사용에서 10만 엔티티 워크스페이스가 관찰되면서 그 사이가 경험적 공백이 됐고, 라벨 10만 개 코퍼스를 만들어 다시 측정했습니다. 코퍼스는 실제 추출 라벨 23,859개를 코어로 두고 위키 타이틀과 기업명으로 방해 요소를 채운 뒤, 정답이 있는 통제 클러스터 300개를 주입한 것입니다. 질의는 350개를 계층별로 고정했습니다.
여기서 세 가지가 나왔습니다.
소규모 결과는 재현됐지만 전부는 아닙니다. 상위 10개 컷오프에서는 모든 규모에서 유의하게 이겼고 이득은 규모와 함께 커졌습니다. 그런데 상위 40개 컷오프에서는 유의하게 졌습니다. 원인을 계층별로 분해하니 한 계층에서만 손실이 났습니다. 타깃 자신이 밀집한 시리즈의 일원인 경우, CSLS가 클러스터 전체를 강등하면서 정답을 중위 랭크 21위에서 854위로 밀어냈습니다. 상위 10개만 보면 비용이 0으로 보이지만, 제품은 상위 40개까지 소비하므로 실손입니다.
수리는 열 줄이었습니다. 원본 코사인 유사도 1위 후보에게는 CSLS 강등과 무관하게 시드 한 자리를 보장하는 플로어를 넣었습니다. 손실 계층의 절반 이상을 회복하면서 다른 계층의 이득은 전부 보존됐고, 상위 40개 컷오프는 이식 전과 통계적으로 무차이가 됐습니다.
정확도를 올리면 오히려 나빠집니다. 이웃 밀도를 샘플링이 아니라 전수로 정확히 계산하는 오라클 조건이 샘플링 조건보다 일관되게 나빴습니다(46.9% 대 38.9%). 샘플링이 진짜 최근접을 놓쳐 밀도를 낮게 추정하는데, 그 편향이 강등 강도를 완화하는 방향으로 작동합니다. 추정 충실도를 개선하는 것은 이 시스템에서 품질 개선이 아니라 악화이며, 코드에 그 취지의 주석과 함께 샘플 크기를 고정했습니다.
사전 기준의 모호점을 그대로 기록한 것
이 규모 검증에는 사전 판정 기준을 등록해두었는데, 그 기준이 지표를 시드 단계로 볼지 최종 랭킹으로 볼지 못 박지 않았습니다. 시드 단계 기준이면 원래 구현은 전체 유의 마이너스였고, 최종 랭킹 기준이면 상위 10개는 통과하고 상위 40개는 실패입니다.
결정 지표는 제품이 실제로 소비하는 것으로 확정했습니다. 다만 그 확정이 결과를 본 뒤에 이루어졌다는 사실을 문서에 그대로 남겼습니다. 사전 등록의 값은 기준을 못 박는 데 있지 못 박았다고 주장하는 데 있지 않습니다.
왜 이 결과를 채택했는가
지표가 올랐다는 것만으로는 채택하지 않습니다. 이 경우 채택한 이유는 원인이 설명되기 때문입니다. 관측된 실패(허브가 상위를 차지함), 진단(거리 집중), 개입(허브 보정), 결과(recall 상승)가 하나의 인과로 이어지고 각 단계가 따로 확인됩니다. 원인을 설명할 수 없는 개선은 다음 실행에서 유지될지 예측할 근거가 없어 채택하지 않습니다.
한계
- CSLS의 이웃 수는 이 코퍼스에서 조정한 값입니다. 분포가 다른 코퍼스에서 같은 값이 최적이라는 근거는 없습니다.
- recall@10이 오른다고 최종 답변 품질이 같은 비율로 오르지는 않습니다. 그래서 end-to-end를 따로 측정했고 위 표에 함께 적었습니다.
- 이 개선은 검색 시딩 단계에 한정됩니다. 랭킹 이후 단계의 실패 모드는 별도 문제입니다.
- 플로어 수리가 구하지 못하는 잔여 케이스가 있습니다. 정답이 원본 코사인 2위에서 8위 사이인 경우이며, 자리를 늘리면 다시 클러스터가 상위를 점유하는 쪽과 맞바꾸는 트레이드입니다.
- 규모 검증은 10만까지입니다. 20만 이상은 측정하지 않았고, 캡을 다시 조정할 때는 이 하니스를 다시 돌려야 합니다.
참고
Radovanović, Nanopoulos, Ivanović, Hubs in Space: Popular Nearest Neighbors in High-Dimensional Data, JMLR 11 (2010).
측정 기록
| 항목 | 값 |
|---|---|
| 최초 측정 | 2026년 6월 28일, 엔티티 약 300개, 6케이스를 3회 평균, 매 실행마다 재추출 |
| 규모 검증 | 2026년 7월 16일, 라벨 100,000개(임베딩 결손 0), 질의 350개, 실그래프 41개 통합 (노드 109,471 / 엔티티 101,812) |
| 임베딩 | google/gemini-embedding-2, 3,072차원, OpenRouter, 96개 배치 — 프로덕션과 동일 경로 |
| 하니스 | flooding_fix_ab (최초), src-tauri/src/tagging/csls_scale_eval.rs (규모) — 둘 다 #[ignore] 라이브 테스트 |
| 조건 | 프로덕션 함수 lexical_seeds / semantic_seeds / personalized_pagerank를 직접 호출. eval 복제본이 아님 |
| 통계 | 전 조건 동일 질의 페어드, recall 델타에 부트스트랩 95% 신뢰구간(1만 리샘플), McNemar 불일치 카운트, 계층별 분해 |
| API 비용 | 규모 검증 약 $2.6 (증강 임베딩 $0.095 + 질의 생성·임베딩) |
규모 검증의 원자료 1.4GB는 2026년 7월 16일에 삭제했고, 위 수치가 그 산출물의 집계입니다. 재현 스크립트는 저장소의 docs/csls-scale-eval/ 아래에 prep_corpus, pick_targets, embed_labels, gen_queries 순으로 남아 있습니다.
비트 단위 재현은 불가능합니다. 코퍼스가 그 시점의 앱 DB 라벨과 임베딩, 위키 덤프의 latest, 그리고 온도 0이 아닌 LLM 질의 생성에 의존하기 때문입니다. 재실행은 새 코퍼스에서 같은 방향을 재검증하는 것이지 같은 숫자를 다시 얻는 것이 아닙니다. 샘플링이 해시맵 순회 순서에 의존해 시맨틱 회수율이 실행 간 몇 pp씩 흔들리는 것도 확인했으며, 판정에 쓴 페어드 델타와 신뢰구간은 그 지터에도 안정적이었습니다.
측정 기록 원본은 Consilience 저장소의 docs/details/graphrag-seeding-csls.md와 docs/details/csls-scale-eval-2026-07.md에 있습니다.
무엇을 측정한 것인가
- Consilience
세계 최초의 범용 온톨로지 OS — 마크다운 문서에서 지식그래프를 자동으로 구축하고, 그 그래프를 대상으로 에이전트가 추론합니다