기술공부/LLM

BM25 b(Best Matching 25)와 Opensearch

넹넹선생님 2025. 3. 26. 08:02
728x90
반응형

BM25 (Best Matching 25)는 OpenSearch와 Elasticsearch에서 기본적으로 사용하는 문서와 쿼리 간의 관련성 점수 계산 알고리즘입니다.

Lexical Search에서 match 쿼리를 실행했을 때, 각 문서의 _score가 바로 이 BM25 점수입니다.


✅ 핵심 개념 먼저 요약

용어 설명

TF (Term Frequency) 쿼리 단어가 문서 내에 얼마나 많이 나왔는가
IDF (Inverse Document Frequency) 해당 단어가 전체 문서 중 얼마나 희귀한가
문서 길이 보정 너무 긴 문서는 단어 많이 포함되기 쉬우므로 패널티 줌
최종 점수 = TF × IDF × 보정계수  

🧮 BM25 수식

단어 qiq_i에 대해 문서 DD와 쿼리 QQ 간의 점수:

$score(D,Q)=∑i=1nIDF(qi)⋅f(qi,D)⋅(k1+1)f(qi,D)+k1⋅(1−b+b⋅∣D∣avgD)\text{score}(D, Q) \\ = \sum_{i=1}^{n} IDF(q_i) \cdot \frac{f(q_i, D) \cdot (k_1 + 1)}{f(q_i, D) + k_1 \cdot (1 - b + b \cdot \frac{|D|}{avgD})}$

각 요소 설명:

기호 의미

$f(qi,D)f(q_i, D)$ 문서 D에서 단어 qiq_i의 빈도 (TF)
( D
$avgDavgD$ 전체 문서들의 평균 길이
$k1k_1$
TF에 대한 민감도 조절 (보통 1.2~2.0, 기본값 1.2)
$bb$ 문서 길이에 대한 보정 정도 (보통 0.75)
$IDF(qi)IDF(q_i)$ 단어 qiq_i의 역문서빈도 값 (아래 참고)

📌 IDF 수식

$IDF(qi)=log⁡(N−n(qi)+0.5n(qi)+0.5+1)IDF(q_i) \\ = \log \left( \frac{N - n(q_i) + 0.5}{n(q_i) + 0.5} + 1 \right)$

기호 의미

$NN$ 전체 문서 수
$n(qi)n(q_i)$ 단어 qiq_i를 포함한 문서 수

→ 흔한 단어는 IDF 값이 낮아지고, 드문 단어는 IDF가 커져서 점수가 올라갑니다.


✅ 예제로 이해하기

🔹 상황

  • 전체 문서 수: 10,000개
  • 평균 문서 길이: 100개 단어
  • 문서 A:
    • 길이: 120단어
    • "search"라는 단어가 4번 등장
  • "search" 단어가 전체 문서 중 500개에 등장

🔹 계산

  1. TF (빈도): 4
  2. 문서 길이 보정:

$4⋅(1.2+1)4+1.2⋅(1−0.75+0.75⋅120100) \\ =8.84+1.2⋅(0.25+0.9) \\=8.84+1.2⋅1.15≈8.85.38≈1.64\frac{4 \cdot (1.2 + 1)}{4 + 1.2 \cdot (1 - 0.75 + 0.75 \cdot \frac{120}{100})} \\ = \frac{8.8}{4 + 1.2 \cdot (0.25 + 0.9)} \\ = \frac{8.8}{4 + 1.2 \cdot 1.15} \approx \frac{8.8}{5.38} \approx 1.64$

  1. IDF:

$log⁡(10000−500+0.5500+0.5+1)=log⁡(9500.5500.5+1) \\ ≈log⁡(19.0+1) \\ ≈log⁡(20) \\ ≈3.0\log \left( \frac{10000 - 500 + 0.5}{500 + 0.5} + 1 \right) \\ = \log \left( \frac{9500.5}{500.5} + 1 \right) \approx \log(19.0 + 1) \approx \log(20) \approx 3.0$

  1. BM25 점수:

$3.0⋅1.64=4.923.0 \cdot 1.64 = 4.92$


✅ 왜 중요한가?

특징 효과

단어가 많이 등장할수록 점수 ↑
드문 단어일수록 (높은 IDF) 점수 ↑
짧은 문서일수록 점수 ↑ (정확한 문서일 가능성 ↑)
흔한 단어 or 너무 긴 문서 점수 ↓

BM25는 단순한 단어 포함 여부를 넘어서, 얼마나 핵심적인 단어인가를 반영해서 점수를 매기는 것이 장점입니다.


✅ OpenSearch에서 어떻게 쓰이는가?

{
  "match": {
    "text": {
      "query": "search engine",
      "operator": "or"
    }
  }
}

이 쿼리를 날리면 OpenSearch는:

  1. "search", "engine" 단어를 Analyzer로 토큰화
  2. 각 단어가 문서에 얼마나 자주, 얼마나 희귀하게 등장했는지 계산
  3. BM25 점수를 구해 _score 필드에 저장
  4. _score 높은 순으로 결과 반환

궁금한 점:

  • k1, b 파라미터를 어떻게 조정하는지?
  • BM25 대신 다른 점수 모델 사용 가능한가?
  • BM25 튜닝해서 내 서비스에 맞추고 싶은데 어떻게 해야 하나?

이런 부분도 알려드릴 수 있어요! 더 보고 싶은 내용 있으실까요?

728x90
반응형