Skip to content

Latest commit

 

History

History
403 lines (381 loc) · 10.1 KB

5.5-exact-value.md

File metadata and controls

403 lines (381 loc) · 10.1 KB
description
이 문서의 허가되지 않은 무단 복제나 배포 및 출판을 금지합니다. 본 문서의 내용 및 도표 등을 인용하고자 하는 경우 출처를 명시하고 김종민([email protected])에게 사용 내용을 알려주시기 바랍니다.

5.5 정확값 쿼리 - Exact Value Query

지금까지 살펴본 풀 텍스트 검색은 스코어 점수 기반으로 **정확도(relevancy)**가 높은 결과부터 가져옵니다. Elasticsearch는 정확도를 고려하는 풀 텍스트 외에도 검색 조건의 참 / 거짓 여부만 판별해서 결과를 가져오는 것이 가능합니다. 풀 텍스트와 상반되는 이 특성을 정확값(Exact Value) 이라고 하는데 말 그대로 값이 정확히 일치 하는지의 여부 만을 따지는 검색입니다. Exact Value 에는 term, range 와 같은 쿼리들이 이 부분에 속하며, 스코어를 계산하지 않기 때문에 보통 bool 쿼리의 filter 내부에서 사용하게 됩니다.

bool : filter

bool쿼리의 filter 안에 하위 쿼리를 사용하면 스코어에 영향을 주지 않습니다. 다음 3개의 검색 결과를 비교 해 보도록 하겠습니다.

{% tabs %} {% tab title="request" %} {% code title="match 쿼리로 fox 검색" %}

GET my_index/_search
{
  "query": {
    "match": {
      "message": "fox"
    }
  }
}

{% endcode %} {% endtab %}

{% tab title="response" %} {% code title="match 쿼리로 fox 검색 결과" %}

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

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

{% tabs %} {% tab title="request" %} {% code title="match 쿼리로 fox 와 quick 검색" %}

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "message": "fox"
          }
        },
        {
          "match": {
            "message": "quick"
          }
        }
      ]
    }
  }
}

{% endcode %} {% endtab %}

{% tab title="response" %} {% code title="match 쿼리로 fox 와 quick 검색 결과" %}

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 0.9468958,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.9468958,
        "_source" : {
          "message" : "The quick brown fox"
        }
      },
      {
        "_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"
        }
      }
    ]
  }
}

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

{% tabs %} {% tab title="request" %} {% code title="must 로 fox 및 filter 으로 quick 검색" %}

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "message": "fox"
          }
        }
      ],
      "filter": [
        {
          "match": {
            "message": "quick"
          }
        }
      ]
    }
  }
}

{% endcode %} {% endtab %}

{% tab title="response" %} {% code title="must 로 fox 및 filter 으로 quick 검색 결과" %}

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

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

첫번째는 match 쿼리로 fox 를 검색했을 때 4개의 도큐먼트가 검색되었고 가장 높은 스코어는 "_score" : 0.32951736 입니다. 두번째는 검색에 match 쿼리로 quick 을 추가했을 때 3개의 도큐먼트가 검색되었고 가장 높은 스코어는 "_score" : 0.9468958 입니다. 세번째는 첫번째의 검색에 filter 구문 안에 quick 을 추가했는데 3개의 도큐먼트가 검색되었고 가장 높은 스코어는 첫번째 쿼리와 같은 "_score" : 0.32951736 입니다.

이렇게 filter는 검색에 조건은 추가하지만 스코어에는 영향을 주지 않도록 제어할 때 사용합니다. 보통 쇼핑몰에서 검색어로 정확도가 높은 상품명을 검색하면서 생산 업체를 다시 필터링 하는 등의 용도로 사용이 가능합니다.

filter 내부에서 must_not 과 같은 다른 bool 쿼리를 포함하려면 filter 내부에 bool 쿼리를 먼저 넣고 그 안에 다시 must_not 을 넣어야 합니다. 다음은 fox 를 포함하면서 dog 는 포함하지 않는 도큐먼트를 검색하는 쿼리입니다. dog 를 제외하는 must_not 쿼리가 filter 안에 있기 때문에 스코어는 fox 에만 영향을 받습니다.

{% tabs %} {% tab title="request" %} {% code title="must 로 fox 검색 후 must_not 으로 dog 제거" %}

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "message": "fox"
          }
        }
      ],
      "filter": [
        {
          "bool": {
            "must_not": [
              {
                "match": {
                  "message": "dog"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

{% endcode %} {% endtab %}

{% tab title="response" %} {% code title="must 로 fox 검색 후 must_not 으로 dog 제거 결과" %}

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.32951736,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.32951736,
        "_source" : {
          "message" : "The quick brown fox"
        }
      }
    ]
  }
}

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

위 검색에서 결과는 하나만 리턴 되었지만 스코어는 "_score" : 0.32951736으로 match 쿼리로 fox만 검색했을 때의 결과와 동일합니다.

keyword

문자열 데이터는 keyword 형식으로 저장하여 정확값 검색이 가능합니다. Keyword 에 대해서는 뒤에 매핑에서 다시 설명 하겠습니다. 아래의 쿼리는 message 필드값이 "Brown fox brown dog" 문자열과 공백, 대소문자까지 정확히 일치하는 데이터만을 결과로 리턴합니다.

{% tabs %} {% tab title="request" %} {% code title="keyword 필드 검색" %}

GET my_index/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "match": {
            "message.keyword": "Brown fox brown dog"
          }
        }
      ]
    }
  }
}

{% endcode %} {% endtab %}

{% tab title="response" %} {% code title="keyword 필드 검색 결과" %}

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.0,
        "_source" : {
          "message" : "Brown fox brown dog"
        }
      }
    ]
  }
}

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

keyword 타입으로 저장된 필드는 스코어를 계산하지 않고 정확값의 일치 여부만을 따지기 때문에 스코어가 "_score" : 0.0 으로 나오게 됩니다. 스코어를 계산하지 않기 때문에 keyword 값을 검색 할 때는 filter 구문 안에 넣도록 합니다.

{% hint style="info" %} filter 안에 넣은 검색 조건들은 스코어를 계산하지 않지만 캐싱이 되기 때문에 쿼리가 더 가볍고 빠르게 실행됩니다. keyword 와 뒤에 설명할 range 쿼리와 같이 스코어 계산이 필요하지 않은 쿼리들은 모두 filter 안에 넣어서 실행하는 것이 좋습니다. {% endhint %}