본문 바로가기
C.W.K.
Stream
Lesson 03 of 05 · published

벡터 검색과 순위 융합

~13 min · vectors, rrf, fusion, hybrid, embeddings

Level 0꺼진 심지
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"키워드는 입력한 단어를 찾고, 벡터는 표현이 달라도 같은 뜻을 찾아. 둘을 합치면 하나만 고를 필요가 없어."

벡터는 단어가 다른 같은 생각을 찾아

임베딩 모델은 텍스트를 고차원 공간의 점으로 바꿔. Lantern이 쓰는 벡터는 1024차원이고, 뜻이 가까운 문장들이 서로 가까운 곳에 놓여. 그래서 '시장 공포 속에서 침착함을 유지하는 법'을 검색해도 단어가 하나도 겹치지 않는 '폭락기의 감정 규율' 구절을 찾을 수 있어. BM25가 정확한 단어에 강하다면 벡터는 표현이 다른 같은 의미를 보충해.

두 검색의 점수는 바로 더할 수 없어

BM25 결과와 벡터 결과를 각각 순위로 얻었다고 해보자. BM25 점수와 코사인 유사도는 서로 다른 단위라 숫자 크기를 비교할 수 없어. 억지로 같은 범위에 맞추면 코퍼스가 바뀔 때마다 보정과 가중치를 다시 손봐야 해. 하이브리드 검색에서 가장 쉽게 깨지는 부분이 바로 이 점수 혼합이야.

RRF는 점수를 버리고 등수만 사용해

Reciprocal Rank Fusion은 각 목록에서의 위치로 1 / (k + rank)를 계산해 더해. k는 보통 60을 쓰고, 한 목록에서 상위에 있거나 두 목록 모두에 등장한 결과가 높은 합산값을 얻어. BM25 점수와 코사인 값을 산식에 넣지 않으니 서로 다른 척도를 맞출 필요가 없어.

서로 다른 검색 결과를 합칠 때는 원점수가 아니라 순위를 합쳐. 세 번째라는 위치는 어느 목록에서든 같은 뜻이지만, 서로 다른 알고리즘의 0.8은 같은 품질을 뜻하지 않아. RRF는 이 차이를 복잡한 보정 없이 피하는 단순하고 강한 방법이야.

화려한 보정보다 단순한 합의가 오래 가

가중치를 학습하고 점수 분포를 교정하는 더 복잡한 방법도 있어. 하지만 RRF는 사실상 상수 하나만으로 서로 다른 척도에 잘 버티고 별도 학습도 필요 없어. 임베딩 서버가 멈추면 키워드 목록 하나만 남았다고 응답에서 밝히고, 서버가 살아 있으면 두 독립된 검색기가 함께 높게 평가한 결과를 위로 올려. 적은 복잡도로 얻는 가치가 커서 기본 융합 방식으로 쓰기 좋아.

특히 두 목록 모두에서 높게 나온 결과는 독립된 두 관점의 동의를 받은 셈이야. 정확한 단어도 맞고 의미도 가깝다는 뜻이니 한쪽에서만 우연히 높게 나온 결과보다 믿을 만해. RRF는 이 합의를 별도 학습 없이 순위 산수만으로 위로 끌어올려.

Code

점수 척도를 맞추지 않고 두 순위를 합치는 RRF 전체 구현·python
def reciprocal_rank_fusion(ranked_lists: list[list[str]], k: int = 60) -> list[str]:
    """Fuse several ranked lists of chunk_ids into one — by RANK, never by score."""
    scores: dict[str, float] = {}
    for lst in ranked_lists:                 # e.g. [bm25_ids, vector_ids]
        for rank, chunk_id in enumerate(lst, start=1):
            scores[chunk_id] = scores.get(chunk_id, 0.0) + 1.0 / (k + rank)
    # Highest fused score first. Appearing high in BOTH lists wins.
    return sorted(scores, key=scores.get, reverse=True)

# Note what never appears: no BM25 score, no cosine similarity, no normalization.
# The two systems' scores were incomparable — so we simply never compared them.
fused = reciprocal_rank_fusion([bm25_hits, vector_hits], k=60)

External links

Exercise

같은 쿼리에 키워드 검색과 벡터 검색이 각각 결과 다섯 개를 돌려줬다고 생각하고, 일부는 겹치고 일부는 다르게 짧은 순위 목록 둘을 손으로 써봐. 종이에 k=60으로 RRF를 적용해. 각 목록에서 결과가 차지한 순위마다 1/(60+rank)를 더하고 다시 정렬해. 두 방법이 모두 높게 고른 결과가 얼마나 올라오는지 봐. 그 합의가 융합의 핵심 가치야.
Hint
한 목록에만 나온 결과는 1/(60+순위) 한 항만 얻고, 두 목록에 모두 나온 결과는 두 항을 더해. 그래서 서로 독립된 두 검색 방식이 함께 높게 평가한 항목이 자연스럽게 위로 올라와.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.