BM25
글자가 겹치는 것을 찾는 검색. 뜻은 이해하지 못한다.
어떻게 동작하나
질문과 청크에서 겹치는 단어의 개수와 희귀도로 점수를 매긴다.
점수 = Σ (겹친 단어마다) 희귀도 × 등장빈도 보정 × 길이 보정
- 희귀도(IDF) — 흔한 단어는 점수가 낮다.
시스템보다ENDURA-5500이 훨씬 값지다 - 등장빈도 — 많이 나올수록 높지만, 무한정 오르진 않는다 (
k1파라미터) - 길이 보정 — 긴 문서는 우연히 겹칠 확률이 높으니 깎는다 (
b파라미터)
강점과 약점
| 강점 | 고유명사·코드·번호에 강하다. 글자가 있으면 바로 잡는다 |
| 약점 | 표현이 다르면 못 찾는다 (사업기간 ↔ 용역기간) |
| 약점 | 긴 질문에서 흔한 단어가 점수를 독식한다 → 아래 |
⚠️ 우리가 겪은 함정 — 질문 안의 사업명
질문이 "〈사업명 10단어〉에서 〈핵심어 1단어〉는?" 형식이면,
사업명을 반복하는 표지·개요 청크가 정답을 이긴다. 겹친 단어가 10개 대 1개니까.
해결: 검색 범위를 대상 문서 1개로 좁힌다. 그 안에서는 사업명이 어디에나 있어 점수 차가 안 생기고, 핵심어가 비로소 변별력을 갖는다.
반대로 질문에서 사업명을 지우면 더 나빠진다 — 엉뚱한 문서가 올라오기 때문. 사업명은 문서 찾기엔 필수, 청크 고르기엔 방해. 두 역할이 충돌한다.
한국어에서 필수 — 형태소 분석
공백으로만 자르면 제안서를과 제안서의가 다른 단어가 된다.
조사를 떼어내야 어휘 매칭이 성립한다. 우리는 kiwipiepy를 쓴다.
우리 프로젝트에서
- 구현:
rank_bm25.BM25Okapi(기본 k1=1.5, b=0.75) - 현재 꺼져 있고, 켜도 동작하지 않는다 — 조건문이 거꾸로 걸려 있음
- 1차 판정: 미채택 (2026-07-29, 164문항, e5-small 베이스)
조건부 결론
BM25가 진 이유가 **“dense가 이미 강해서”**일 수 있다. dense가 약한 임베딩 위에서는 기여가 살아날 여지가 있어, 베이스를 바꾸는 2차 실험에서 다시 잰다. → 검색 실험 결과 §4
| 조건 | dense 단독 | +BM25 | 차이 |
|---|---|---|---|
| 문서 한정 | 0.6402 | 0.6096 | −0.031 |
| 전체 코퍼스 | 0.6359 | 0.6004 | −0.036 |
⚠️ 40문항 예비 측정의 +0.073은 소표본 노이즈였다. 164문항에서 부호가 뒤집혔다.
게이팅(dense가 확신할 땐 BM25 미적용)도 못 살렸다. BM25를 끌수록 좋아지고, 전부 껐을 때가 최고점이었다 → 기여가 순손실.
크로스인코더 리랭커를 켜면 BM25는 수학적으로 무효가 된다. BM25 단독 발굴 청크를 버리는 계약 탓에 후보 집합이 안 바뀌고 순서만 바뀌는데, 리랭커가 그 순서를 자기 점수로 덮어쓴다 → 164문항 전건 동일.
상세 → 검색 실험 결과