# 5.3 정확도 - Relevancy

&#x20; RDBMS 같은 시스템에서는 쿼리 조건에 부합하는 지만 판단하여 결과를 가져올 뿐 각 결과들이 얼마나 정확한지에 대한 판단은 보통 불가능합니다. Elasticsearch 와 같은 풀 텍스트 검색엔진은 검색 결과가 입력된 검색 조건과 얼마나 정확하게 일치하는 지를 계산하는 알고리즘을 가지고 있어 이 정확도를 기반으로 사용자가 가장 원하는 결과를 먼저 보여줄 수 있습니다. 이 정확한 정도를 **relevancy** 라고 합니다 (렐러번시 라고 읽습니다). 한국어로 번역하면 연관성 또는 관련성 이라고 번역이 되는데, 이 책에서는 이해를 돕기 위해 **정확도** 라는 표현을 쓰겠습니다. 스터디 또는 강연 등에서 언급 하실 때는 원래 용어 relevancy 로 사용하실 것을 권장 드립니다.

&#x20; 검색을 할 때 사용자는 찾고자 하는 정확한 결과만 보고싶어 합니다. 검색 조건에 포함 되더라도 사용자가 찾으려는 결과와 상관 없는 결과는 보여주지 않는 것이 좋습니다. 구글 또는 네이버 같은 웹 검색엔진들도 검색을 하면 찾은 결과들 중에 어떤 것이 사용자가 입력한 검색어와 가장 연관성이 있는지를 계산하여 정확도가 가장 높은 결과들 부터 보여줍니다.

### 스코어 (score) 점수

&#x20; Elasticsearch의 검색 결과에는 스코어 점수가 표시가 됩니다. 이 점수는 검색된 결과가 얼마나 검색 조건과 일치하는지를 나타내며 점수가 높은 순으로 결과를 보여줍니다. 다음의 match 쿼리 결과를 살펴보겠습니다.

{% tabs %}
{% tab title="request" %}
{% code title="quick dog 를 포함한 도큐먼트 검색" %}

```javascript
GET my_index/_search
{
  "query": {
    "match": {
      "message": "quick dog"
    }
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="response" %}
{% code title="quick dog 를 포함한 도큐먼트 검색 결과" %}

```javascript
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : 0.8762741,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.8762741,
        "_source" : {
          "message" : "The quick brown fox jumps over the quick dog"
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.6744513,
        "_source" : {
          "message" : "The quick brown fox jumps over the lazy dog"
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.6173784,
        "_source" : {
          "message" : "The quick brown fox"
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 0.35847884,
        "_source" : {
          "message" : "Lazy jumping dog"
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.32951736,
        "_source" : {
          "message" : "Brown fox brown dog"
        }
      }
    ]
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

&#x20; 각 검색 결과의 `_score` 항목에 스코어 점수가 표시되고 이 점수가 높은 결과부터 나타납니다. 그리고 상단의 `max_score`에는 전체 결과 중에서 가장 높은 점수가 표시됩니다. Elasticsearch 는 이 점수를 계산하기 위해 **BM25** 라는 알고리즘을 이용합니다. BM은 Best Matching 을 뜻합니다.

&#x20; 다음은 **BM25**의 계산식입니다.

![BM25 계산식 - 출처: https://en.wikipedia.org/wiki/Okapi\_BM25](/files/-LnoBbY9kk0HSvQyTvvO)

&#x20; 복잡해 보이는 이 계산에는 크게 **TF**, **IDF** 그리고 **Field Length** 총 3가지 요소가 사용됩니다.

### TF (Term Frequency)

&#x20; 구글에서 **"쥬라기 공원"** 이라는 검색어로 검색을 한다고 가정 해 보겠습니다. **"쥬라기 공원"**&#xC774;라는 단어가 **5**번 들어 있는 웹 페이지 보다는 **10**번 들어있는 웹 페이지가 내가 보고싶어 하는 정보가 있는 페이지일 확률이 높을 것입니다. 도큐먼트 내에 검색된 **텀(term)**&#xC774; 더 많을수록 점수가 높아지는 것을 **Term Frequency** 라고 합니다.

&#x20; 앞의 검색에서는 값이 "The **quick** brown fox jumps over the **quick** **dog**" 인 도큐먼트가 텀 **quick**, **dog** 총 세개를 포함하고 있어 가장 점수가 높습니다. 포함하고 있는 텀이 증가할수록 아래 그래프와 같이 TF 값도 증가를 하며, BM25에서는 최대 25까지 증가합니다. 즉 25 이상 부터는 TF 점수의 변화가 없습니다.

![출처 : https://opensourceconnections.com/blog/2015/10/16/bm25-the-next-generation-of-lucene-relevation](/files/-LnoG53-nth6Y7BZkpSG)

### IDF (Inverse Document Frequency)

&#x20; 다시 구글에서 **"쥬라기 공원"** 이라는 검색어로 검색을 했을 때 **"쥬라기"** 또는 **"공원"** 중 어떤 단어든 포함하는 페이지들은 검색 결과에 나타날 수 있을 것입니다. 이 때 전체 검색 결과 중에 **"쥬라기"** 가 포함된 결과는 **10**개 **"공원"**&#xC774; 포함된 결과는 **100**개 라고 가정한다면 흔한 단어인 **"공원"** 보다는 희소한 단어인 **"쥬라기"** 가 검색에 더 중요한 텀일 가능성이 높습니다. 검색한 텀을 포함하고 있는 도큐먼트 개수가 많을수록 그 텀의 자신의 점수가 감소하는 것을 **Inverse Document Frequency** 라고 합니다.

&#x20; 앞의 검색 결과 중 값이 "The **quick** brown fox" 인 도큐먼트와 "Lazy jumping **dog**" 인 도큐먼트는 **quick**과 **dog**가 각각 한 번씩만 들어가지만 전체 인덱스를 놓고 보면 **quick**이 들어간 문서는 **3**개, **dog**이 들어간 문서는 **4**개 가 있어 **quick** 이 들어가 있는 결과가 점수가 높습니다. 전체 인덱스에 포함된 텀이 증가할수록 아래 그래프와 같이 IDF 감소하게 됩니다. (그래서 Inverse 입니다)

![출처 : https://opensourceconnections.com/blog/2015/10/16/bm25-the-next-generation-of-lucene-relevation](/files/-LnoIEr8c1Ghixk14w02)

### Field Length

&#x20; 도큐먼트에서 필드 길이가 큰 필드 보다는 짧은 필드에 있는 텀의 비중이 클 것입니다. 블로그 포스트를 검색하는 경우 검색 하려는 단어가 **제목**과 **내용** 필드에 모두 있는 경우 텍스트 길이가 긴 **내용** 필드 보다는 텍스트 길이가 짧은 **제목** 필드에 검색어를 포함하고 있는 블로그 포스트가 더 점수가 높게 나타납니다. 다음 **lazy** 를 검색한 쿼리의 결과를 살펴보겠습니다.

{% tabs %}
{% tab title="request" %}
{% code title="검색어 lazy 를 포함한 도큐먼트 검색" %}

```javascript
GET my_index/_search
{
  "query": {
    "match": {
      "message": "lazy"
    }
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="response" %}
{% code title="검색어 lazy 를 포함한 도큐먼트 검색 결과" %}

```javascript
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0909162,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 1.0909162,
        "_source" : {
          "message" : "Lazy jumping dog"
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.71425706,
        "_source" : {
          "message" : "The quick brown fox jumps over the lazy dog"
        }
      }
    ]
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

&#x20; 검색 결과에서 **lazy** 를 포함하고 있는 2개 도큐먼트 들이 나타났지만 "The quick brown fox jumps over the lazy dog" 보다 길이가 짧은 "Lazy jumping dog" 가 점수가 더 높게 나타납니다.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://esbook.kimjmin.net/05-search/5.3-relevancy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
