본문 바로가기

프로젝트/여행지 오픈 API

[ElasticSearch] 6. 검색 : 컨텍스트와 쿼리, 유사도

목차

    컨텍스트

    구버전의 엘라스틱서치는 쿼리 컨텍스트와 필터 컨텍스트로 구분되었다고 한다.

    쿼리 컨텍스트는 질의에 대한 유사도를 계산하고 정확한 결과를 구분하고,

    필터 컨텍스트는 유사도가 아닌 일치 여부에 따른 결과만을 계산했다.

     

    두 컨텍스트의 개념에 대해 조금 더 자세히 알아보자.

     

    쿼리 컨텍스트

    - 유사도를 구분하여 검색 (ex : 스코어가 4.5인 검색 결과)

    - 유사도 검색 때문에 검색 속도가 상대적으로 느림

    //Kibana에서 제공하는 샘플 데이터를 사용하여 쿼리컨텍스트를 실행해보자.
    //_search : 엘라스틱에서 제공하는 REST API
    GET kibana_sample_data_ecommerce/_search
    {
      "query": {
        "match": { //전문 검색을 위한 쿼리, 역인덱싱용 용어 검색
          "category": "clothing"
        }
      }
    }

    해당 쿼리 검색어가 존재하는 도큐먼트를 전부 검색한다.

    3927개의 도큐먼트가 유사도 순서대로 검색되었다.

    _score의 경우 유사도와 관련된 지표로, 유사도가 높은 순서대로 도큐먼트가 나타난다.

     

    필터 컨텍스트

    - 질의에 대한 답변이 Boolean (ex: '엘라스틱' 에 대한 검색 결과 : 예 / 아니오)

    - 결과 업데이트가 필요 없기에 캐시 활용 가능 (엘라스틱서치는 기본적으로 힙 메모리의 10% 정도를 캐시에 이용함)

     

    //필터 컨텍스트를 통해 매칭 결과값을 확인하자
    GET kibana_sample_data_ecommerce/_search
    {
      "query": {
        "bool": {
          "filter": {
            "term": {
              "day_of_week": "Friday"
            }
          }
        }
      }
    }

    day of week가 Friday인 값을 추출하였다.

    기존 쿼리 컨텍스트와 달리 유사도가 0.0으로 나오는 것을 확인할 수 있다.

     

    과거에는 이렇게 컨텍스트를 구분하여 사용하였지만, 논리 쿼리가 등장함으로써 해당 필터를 단독으로 사용하기보단 적당히 조합하여 사용하는 방향으로 추세가 이루어져 가고 있다.

    쿼리 스트링과 쿼리 DSL

     

    쿼리 사용방법은 크게 쿼리 스트링과 DSL로 나뉜다.

    스트링의 경우는 한 줄 정도의 간단한 쿼리에 사용하고, 쿼리DSL의 경우 한 줄에 넣기 힘든 복잡한 쿼리에 사용한다.

     

    쿼리 스트링

    쿼리스트링은 기존의 param처럼 URI에 파라미터를 넣어서 간단하게 사용한다.

    샘플 데이터를 통해 직접적인 예시를 확인해보자.

     

    GET kibana_sample_data_ecommerce/_search?q=customer_full_name:Mary
    • kibana_sample_data_ecommerce: kibana_sample_data_ecommerce라는 이름의 Elasticsearch 인덱스를 대상으로 검색한다.
    • _search: Elasticsearch에서 제공하는 검색 API의 엔드포인트다.
    • q=customer_full_name:Mary: q 파라미터는 질의 문자열 쿼리를 나타낸다. 여기서는 customer_full_name 필드의 값이 Mary인 문서를 검색하라는 의미다.

    이처럼 쿼리 스트링은 간단한 검색에 사용하기 좋고, curl 같은 툴에서 한 줄에 작성할 수 있어서 유용하다.

    하지만 복잡한 쿼리는 가독성이 떨어질 수 있다는 점을 유의하자.

     

    쿼리DSL

    쿼리DSL의 경우는 REST API의 요청 본문 안에 JSON 형태로 쿼리를 작성한다. 

    이 경우 엘라스틱 서치의 모든 쿼리 스펙을 지원하기에 강력하게 사용할 수 있다.

     

    //예제로 몇 번 사용해봤던 match 역시도 QueryDSL에 포함된다.
    GET kibana_sample_data_ecommerce/_search
    {
      "query": {
        "match": {
          "customer_full_name": "Mary"
        }
      }
    }

     

    유사도 스코어

    유사도 검색 시 엘라스틱서치는 기본적으로 BM25 알고리즘을 이용하여 계산한다.

    유사도 스코어는 질의와 도큐먼트와의 유사도를 표현하는 값으로, 높을 수록 도큐먼트에 가깝다.

     

    실제 쿼리를 요청 시 스코어가 어떻게 계산되었는지 알아보기 위해 explain 옵션을 추가해 보자.

     

    GET kibana_sample_data_ecommerce/_search
    {
      "query": {
        "match": {
          "products.product_name": "Pants"
        }
      },
      "explain": true
    }

    explains를 통해 유사도를 계산하는 계산식을 확인해볼 수 있었다.

     

    이러한 계산식은 IDF 계산과 TF 계싼이 포함되는데, 간략하게 설명해보자면 다음과 같다.

     

    IDF는 문서 전체에 해당 단어가 얼마나 자주 나오는지('그리고', '이다.' 등의 관사는 의미없지만 자주 나올 확률이 높기 때문이다.) 확인 후 가중치를 낮춘다.

    TF는 특정 용어가 하나의 도큐먼트에 얼마나 많이 등장했는지를 보이는 지표이다. (특정 용어가 하나의 도큐먼트에서 반복된다면 주제와 연관있을 가능성이 높다.)

     

    BM25에서 최종 스코어는 IDF * TF * boost(일반적으로 2.2) 이다.