[Lucene] score 계산식 알아보기.
Elastic/Elasticsearch 2013. 10. 11. 11:25제가 elasticsearch 로 프로젝트를 진행 하고 있습니다.
랭킹과 문서 스코어링 관련해서 문의가 있어서 정확하게 설명을 해줘야 튜닝에 도움이 될 것 같아 글 좀 남겨 봅니다.
검색해 보시면 많은 문서들이 나오는데요.
아래 문서 참고 하시면 좋을 것 같내요.
[참고링크]
http://www.lucenetutorial.com/advanced-topics/scoring.html
http://devyongsik.tistory.com/364 (여긴 울 회사 재화님도 알고 계신 DEV용식님 사이트인데요. 작성 된지 좀 되었지만 이해 하기에는 좋습니다.)
https://lucene.apache.org/core/3_6_2/scoring.html
http://lucene.apache.org/core/4_5_0/core/org/apache/lucene/search/package-summary.html#package_description
http://lucene.apache.org/core/4_5_0/core/org/apache/lucene/search/similarities/TFIDFSimilarity.html
[참고용 소스코드]
Similarity.java
DefaultSimilarity.java
TFIDFSimilarity.java
lucene 이나 elasticsearch 나 기본은 바로 위에 있는 넘들 가지고 similarity 계산을 하게 됩니다.
소스를 보시면 아시겠지만 아래 요소를 가지고 score 를 계산 합니다.
tf
idf
lengthNorm
queryNorm
coord
소스코드에서 식을 뽑아 보면 이렇습니다.
TF |
(float)Math.sqrt(freq) |
IDF |
(float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0)^2 |
lengthNorm |
state.getBoost() * ((float) (1.0 / Math.sqrt(numTerms))) |
queryNorm |
(float)(1.0 / Math.sqrt(sumOfSquaredWeights)) |
coord |
overlap / (float)maxOverlap |
이런건 그냥 위에 나온거 보면 다 나오구요.
검색 질의 시 스코어 계산 유형을 살펴 보겠습니다.
(계산 할 때 위에 식에 넣어서 계산 하기 번거로우니 explain 떠서 나온 값들을 사용해서 계산 하도록 하세요.)
1. 검색어 하나 질의
쉽게는 explain 에서 나온 queryWeight * fieldWeight 를 곱하시면 score 가 나옵니다.
score = (queryWeight * fieldWeight)^2
TFIDFSimilarity.html 에 잘 나와 있죠.
| |||||||
이걸 엑셀 같은 데 식을 넣어서 계산 해 보면 값이 나오게 됩니다.
아래 2번에서 풀어 놓은 식을 참고하세요.
2. 검색어 여러개 질의
score = (queryNorm * SUM( tf * idf^2 * fieldBoost * fieldNorm) )^2
3. 필드 부스팅을 포함한 검색어 질의
쉽게는 아래 처럼 풀어서 이해 하시면 됩니다.
score = ((queryWeight * fieldWeight) + (queryWeight * fieldWeight))^2
-> 필드 부스팅 된 필드의 queryWeight 값은 기본 계산이 되어서 나오지만 같은 필드에 같은 term 으로 했을 경우 기본 queryWeight 에 곱하기 boostScore 만큼 해준다고 보면 됩니다.
여기서 필드 부스팅을 한개가 아닌 여러개를 했다면 (queryWeight * fieldWeight) 이넘을 여러번 계산 해서 더하시면 됩니다.
근데 여기서 궁금한거 하나....
- fieldNorm 과 sumOfSquaredWeights 는 어떻게 구하나요???
소스 코드를 보시면 됩니다.
[fieldNorm]
computeNorm(), encodeNormValue(), decodeNormValue(), NORM_TABLE 을 참고하세요.
풀면 결국 아래와 같이 됩니다.
fieldNorm = NORM_TABLE[(floatToByte315(1/SQRT(fieldTotalTermsNum)) & 0xFF)];
[sumOfSquaredWeights]
말 처럼 이건 각각의 term 에 대해서 더하셔야 합니다.
1번에서 처럼 sigma 가 붙어 있는 걸 잊으시면 안됩니다.
이해를 돕고자 풀면 아래와 같이 됩니다.
queryBoost^2 * SUM( (idf * fieldBoost)^2 )
가볍게 이해 하는 수준으로만 사용하시고 깊이 있게 이해를 하고 싶으신 분들은 소스 코드를 꼭 드려야 보세요. :)