본문 바로가기
ElasticSearch

[ ElasticSearch ] Score 계산과 function_score

by Heesu.lee 2021. 3. 7.

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 이 두값의 조합으로 스코어 값이 줄어드는 기준을 정한다.

 

 

참조

  • diane_at_work 블로그 - 링크
  • kazaana2009 블로그 - 링크
  • 상구리의 기술 블로그 - 링크
  • ElasticSearch 공식 페이지 - 링크

'ElasticSearch' 카테고리의 다른 글

Spring Data Elasticsearch 를 활용한 Search After 구현  (0) 2021.03.01

댓글