ElastiSearch 는 기본적으로 BM25 알고리즘을 이용해 문서에 대한 score 계산을 한다.
BM25 알고리즘
검색 키워드의 빈도수, 문서상의 키워드의 빈도수, 문서의 크기 기준으로 score 를 계산합니다.
Term Frequency
문서 내에서 자주 등장하는 단어(Term) 에 가중치를 높게 부여
Inverse Document Frequency
많은 문서에서 등장하는 단어의 가중치는 낮추고, 일부 문서에만 등장하는 단어에 대해 높은 가중치 부여
Field-Length Norm
두개 이상의 문서에서 동일한 키워드가 동일한 빈도수로 등장한다고 가정할 때, 문서의 길이가 작은 문서에 더 높은 가중치를 부여
실제 검색 요청시 explain=true 를 Query Parameter 로 넘기면, Score 가 어떻게 계산되었는지 자세히 보여준다.
<검색 요청>
GET /account/_search?explain=true
{
"query": {
"match": {
"state": "CO"
}
}
}
<검색 결과>
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 14,
"relation" : "eq"
},
"max_score" : 4.2346063,
"hits" : [
{
"_shard" : "[account][0]",
"_node" : "0360XEgFS0evHF75ZwdEuQ",
"_index" : "account",
"_type" : "_doc",
"_id" : "330",
"_score" : 4.2346063,
"_source" : {
"account_number" : 330,
"balance" : 41620,
"firstname" : "Yvette",
"lastname" : "Browning",
"age" : 34,
"gender" : "F",
"address" : "431 Beekman Place",
"employer" : "Marketoid",
"email" : "yvettebrowning@marketoid.com",
"city" : "Talpa",
"state" : "CO"
},
"_explanation" : {
"value" : 4.2346063,
"description" : "weight(state:CO in 66) [PerFieldSimilarity], result of:",
"details" : [
{
"value" : 4.2346063,
"description" : "score(freq=1.0), computed as boost * idf * tf from:",
"details" : [
{
"value" : 2.2,
"description" : "boost",
"details" : [ ]
},
{
"value" : 4.2346063,
"description" : "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
"details" : [
{
"value" : 14,
"description" : "n, number of documents containing term",
"details" : [ ]
},
{
"value" : 1000,
"description" : "N, total number of documents with field",
"details" : [ ]
}
]
},
{
"value" : 0.45454544,
"description" : "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
"details" : [
{
"value" : 1.0,
"description" : "freq, occurrences of term within document",
"details" : [ ]
},
{
"value" : 1.2,
"description" : "k1, term saturation parameter",
"details" : [ ]
},
{
"value" : 0.75,
"description" : "b, length normalization parameter",
"details" : [ ]
},
{
"value" : 1.0,
"description" : "dl, length of field",
"details" : [ ]
},
{
"value" : 1.0,
"description" : "avgdl, average length of field",
"details" : [ ]
}
]
}
]
}
]
}
},
...
}
위의 검색 요청 결과에서 _explanation 부분에서 확인할 수 있다.
BM25 알고리즘에서 문서 점수 계산식 score = TF * tfNorm
즉, ElasticSearch 기본적으로 검색된 문서에 매칭된 키워드 수가 자주 반복될 수록, 또 평균 필드 길이보다 검색된 문서의 필드가 길수록 score 가 올라간다.
기존 TF-IDF 보다 BM25 가 더 정교한 score 계산을 하기 때문에 ES 버전 6.3 부터는 해당 알고리즘을 사용하고 있다.
그렇다면, ElasticSearch 의 점수 계산을 바꿀 수는 없을까?
단순 용어에 대한 빈도수와 필드를 부스팅하여 스코어를 조정하는 것은 한계를 가지고 있다.
좀 더 유연하게 점수를 조절할 수 있는 방식으로는 function_score 를 이용한 쿼리이다.
※ 참고사항
만약, 검색 요청 시 sort 필드를 사용하게 되면 따로 score 점수가 반환되지 않는다.
sort 필드 사용하며 score 계산을 null 로 반환되는 것을 방지하기 위해 "track_scores" : true 를 지정해주면 된다.
function_score
boost_factor
- 가장 간단한 함수 - 단순 상수를 곱하여 계산
- 필터를 이용하여 부스팅할 문서를 결정
field_value_factor
- 숫자형 필드의 값을 스코어에 이용
- 대표적으로 카운트된 값 등의 숫자형 필드를 검색 결과에 이용할 때 사용
script_score
- 스크립트 표현식을 사용하여 문서의 다른 숫자 필드 값에서 파생 된 계산으로 다른 쿼리를 래핑하고 선택적으로 점수를 사용자가 지정 가능
- 가장 자유도가 높은 스코어링 방식
random_score
- 문서를 랜덤하게 정렬하고 싶을 때 사용
- seed 값을 동일하게 주면 동일한 결과가 나옴
decay function
- 특정 필드의 값을 이용하여 스코어를 점진적으로 줄여 나가는 함수
- 예) 등록된 날짜가 오래된 정보일 수록 스코어를 줄여나가기, 거리가 멀리 있을 수록 스코어를 줄여나가기
- decay 함수 종류
- linear
- gauss
- exp
- decay 함수 형식
{
“TYPE”: {
“FIELD_NAME”: {
“origin”: “…”,
“offset”: “…”,
“scale”: “…”,
“decay”: “…”
}
}
}
- offset: orgin 으로부터 스코어가 줄어들지 않는 구간의 거리
- origin: 함수 곡선의 중심, 가장 스코어가 높은 지점
- scale: origin 으로부터 멀어지는 단위
- decay: scale 당 줄어드는 단위
※ scale & decay 이 두값의 조합으로 스코어 값이 줄어드는 기준을 정한다.
참조
'ElasticSearch' 카테고리의 다른 글
Spring Data Elasticsearch 를 활용한 Search After 구현 (0) | 2021.03.01 |
---|
댓글