본문 바로가기

Monitoring Tools/ELK Stack

[elasticsearch] Query DSL 관련성 점수(Relevance score)

반응형

elasticsearch는 검색 시 query 절 별로 관련성 점수(Relevance score)를 내고 높은 점수 순으로 나열한다.
관련성 점수(Relevance score) 는 "_score" 라는 API 메타데이터 필드에서 반환되는 양의 소수점 숫자로 표현된다.

{
        "_shard": "[cf-spectrum-log-2024.06.25][0]",
        "_node": "7eOtUDXAQGe3ZgXsFQBCLg",
        "_index": "cf-spectrum-log-2024.06.25",
        "_type": "_doc",
        "_id": "cdfDT5ABhXQXL4awCoxV",
        "_score": 4.212528,
...

 

관련성 점수(Relevance score)에 사용되는 알고리즘은 다음과 같은 요소(TF/IDF)들을 고려한다.

1. Term frequency(TF)
 - 해당 용어가 필드에 노출되는 빈도. 빈도가 높을 수록 관련성 점수가 높다.
2. Inverse document frequency(IDF)
 - 해당 용어가 다른 문서(document)에도 자주 등장한다면 관련성 점수가 낮다.
 - 즉, 다른 문서와 비교하여 자주 등장하지 않는 용어 일수록 관련성 점수가 높다.
3. Field-length norm
 - 필드 값 길이가 짧을 수록 관련성 점수가 높다.

참조 : https://www.elastic.co/guide/en/elasticsearch/guide/master/relevance-intro.html


match query를 사용하여 검색할 때 위 세가지 요소로 책정된 점수를 확인 할수 있다.

curl -XGET 127.0.0.1:9200/search_index/_search?explain=true \
-H 'Content-Type:application/json' \
-d @test.json

 

...
        ###### 점수 계산 설명 시작 ######
        "_explanation": {
	      ###### 최종 스코어 ######
          "value": 4.212528,
          "description": "weight(*** in 131509) [PerFieldSimilarity], result of:",
          "details": [
            {
              "value": 4.212528,
              "description": "score(freq=2.0), computed as boost * idf * tf from:",
              "details": [
                {
                  "value": 2.2,
                  "description": "boost",
                  "details": []
                },
                {
		          ###### IDF ######
                  "value": 2.7842128,
                  "description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
                  "details": [
                    {
                      "value": 51408,
                      "description": "n, number of documents containing term",
                      "details": []
                    },
                    {
                      "value": 832152,
                      "description": "N, total number of documents with field",
                      "details": []
                    }
                  ]
                },
                {
		          ###### TF ######
                  "value": 0.68772954,
                  "description": "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
                  "details": [
                    {
                      "value": 2,
                      "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": 4,
                      "description": "dl, length of field",
                      "details": []
                    },
                    {
                      "value": 5.9198847,
                      "description": "avgdl, average length of field",
                      "details": []
                    }
                  ]
                }
              ]
            }
          ]
        }
      },

 

원하는 검색에 근접하기 위하여 boost를 사용하여 쿼리 절 별로 가중치를 둘 수 있다.
아래와 같이 match_phrase 절에 boost값을 주어 어느 쿼리에 중점을 두어야 할지 결정 할 수 있다.
boost 2를 준 경우 2배의 가중치로 계산된다.

{
  "_source": [ "dfg","sdf","asd"],
  "query": {
    "bool": {
      "should": [
        { 
          "match": {
            "asd": {
              "query": "aaa"
            } 
          }
        },
        {
          "match_phrase": {
            "sdf": {
              "query": "qwe qw",
              "boost": 2
            }
          }
        }
      ]
    }
  },
  "from": 0,
  "size": 2
}

bool 을 사용하여 match, match_phrase query를 조합하 였으며 match_phrase query절에 boost 2로 가중치를 주었다.

참고 : _source : 표출하고자 하는 필드. "dfg,"sdf","asd" 세 필드만 표출된다.

 

관련성 점수는 Query DSL에서 query절이 query context에서 실행되는지 filter context 에서 실행되는 지에 따라 달라진다.



1. query context
 - query context에서 실행되는 query절은 "이 doc와 이 query 절이 얼마나 잘 일치하는가?"에 대한 질문에 응답한다. "얼마나" 라는 말에 표현되어 있드시 _score 메타데이터 필드의 관련성 점수도 함께 계산한다.
2. filter context
 - filter context에서 실행되는 query절은 "이 doc와 이 query 절이 일치하는가?"에 대한 질문에 응답한다. 답은 yes/no 로 표현되며 관련성 점수도 계산하지 않는다.

참고 : https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-filter-context.html

 

query context, filter context 은 kibana GUI - Discover - 검색하는 부분에서 "Search"는 query context, "Add filter" 는 filter context로 생각할 수 있다.

 

다음의 예로 query context, filter context 의 차이점을 살펴 볼 수 있다.


1. title 필드에 Search 라는 단어가 포함되어 있는가?
2. content 필드에 Elasticsearch 라는 단어가 포함되어 있는가?
3. status 필드 값이 published 와 일치하는가?
4. publish_date 필드가 2015년 1월 1일보다 큰가?

GET /_search
{
  ### query context ###
  "query": { 
    "bool": { 
      "must": [
        { "match": { "title":   "Search"        }},
        { "match": { "content": "Elasticsearch" }}
      ],
      ### filter context ###
      "filter": [ 
        { "term":  { "status": "published" }},
        { "range": { "publish_date": { "gte": "2015-01-01" }}}
      ]
    }
  }
}


1,2번은 match query를 써서 포함여부가 얼마나 정확한지를 관련성 점수를 책정한다.
3,4번은 그렇다, 그렇지 않다로 표현되며 관련성 점수를 책정하지 않는다.

 

반응형