[ElasticSearch] 검색과 쿼리 (QueryDSL) - 2

donghyeok·2022년 12월 28일

ElasticSearch

목록 보기
5/8

4. Bool - should

bool 쿼리의 should는 검색 점수를 조정하기 위해 사용한다.
만약 match 쿼리로 fox를 포함하고 있는 도큐먼트를 찾고 싶은데 이 결과들 중 lazy가 포함된 결과에 가중치를 줘서 상위로 올리고 싶다면 다음과 같이 작성이 가능하다.

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

should는 match phrase와 함께 유용하게 사용가능하다.
쇼핑몰 검색 같은 케이스에서는 보통 검색어로 입력된 단어가 하나라도 포함된 결과는 모두 가져오게 되는데, 이 때 검색 결과 중 입력한 검색어 전체 문장이 정확히 일치하는 결과를 맨 상위에 위치시키면 수준 높은 결과를 제공할 수 있다.

다음은 lazy 또는 dog중 하나라도 포함된 문서를 모두 검색하면서 lazy dog구문을 정확히 포함하는 결과들을 가장 상위로 가져간다.

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "message": {
              "query": "lazy dog"
            }
          }
        }
      ],
      "should": [
        {
          "match_phrase": {
            "message": "lazy dog"
          }
        }
      ]
    }
  }
}

추가로, slop 파라미터를 이용해 좀 더 유동적인 검색이 가능하다.

5. 정확값 쿼리 - Exact Value Query

지금까지 살펴본 풀 텍스트 검색은 스코어 기반으로 relevancy가 높은 결과부터 가져온다. ES는 정확도를 고려하는 풀 텍스트 외에도 검색 조건의 참/거짓 여부만 판별해서 결과를 가져오기가 가능하다. Exact Value는 말 그대로 정확히 일치 하는지의 여부만을 따진다. Exact Value에는 term, range와 같은 쿼리들이 속하며, 스코어를 게산하지 않기 때문에 보통 bool 쿼리 filter 내부에 사용한다.

bool : filter

filter는 검색에 조건으로 추가하지만 스코어에 영향을 주지 않도록 제어하기 위해 사용한다.
다음 3개의 검색 결과를 비교해보면 편하다. (편의상 JSON 형식을 줄여쓴다.

  1. match "fox"
  2. must (match "fox" "quick")
  3. must (match "fox") filter (match "quick")

1번 쿼리에서는 4개의 도큐먼트가 검색되고 가장 높은 스코어는 0.329이다
2번 쿼리에서는 3개의 도큐먼트가 검색되고 가장 높은 스코어는 0.946이다.
3번 쿼리에서는 3개의 도큐먼트가 검색되고 가장 높은 스코어는 0.329이다.
이렇게 filter는 스코어 영향을 주지않고 검색 조건에 포함시키기 위한 파라미터이다.

keyword

문자열 데이터는 keyword 형식으로 저장하여 정확값 검색이 가능하다.
아래의 쿼리는 필드값이 Brown fox brown dog 문자열과 공백, 대소문자까지 정확히 일치하는 데이터만을 결과로 리턴한다.

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

keyword 타입으로 저장된 필드는 스코어를 계산하지 않고 정확값의 일치 여부만 따지기 때문에 스코어가 0으로 나오게 된다.
스코어를 계산하지 않기 때문에 filter 내부에 넣는 걸 추천한다. (filter 내부 조건은 캐싱이 되기 때문에 빠르게 실행됨)

6. 범위 쿼리 - Range Query

지금까지는 문자열 필드들의 검색에 대해 보았다. ES는 이외에도 숫자, 날짜 형식들의 저장이 가능하다. 숫자, 날짜 형식은 range 쿼리를 이용해서 검색을 한다.
range 쿼리는 range : { <필드명> : { <파라미터>: <값> } }으로 입력된다.
range 쿼리 파라미터는 아래 4가지가 있다.

gte (이상), gt (초과), lte (이하), lt (미만)

아래는 price 필드값이 700 이상, 900 미만인 데이터를 검색하는 쿼리이다.

GET phones/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 700,
        "lt": 900
      }
    }
  }
}

날짜 검색

날짜 검색도 동일하게 4가지 파라미터를 이용하여 검색이 가능하다.
range 쿼리는 기본적으로 정확도를 계산하지 않는다.
하지만 기준점에서 가깝거나 멀수록 스코어를 적용하고 싶다면 function_score 쿼리를 사용할 수 있다.

날짜 형식은 기본적으로 'yyyy-mm-dd' 형식으로 사용하지만 상황에 따라 변형하여 사용 가능하다.
format 옵션을 이용하여 아래처럼 여러 형식을 사용 가능하다.

GET phones/_search
{
  "query": {
    "range": {
      "date": {
        "gt": "31/12/2015",
        "lt": "2018",
        "format": "dd/MM/yyyy||yyyy"
      }
    }
  }
}

또한 날짜를 계산할 수도 있는데 다음과 같은 예약어들을 사용하여 계산 가능하다

now(현재시간), y(년), M(월), d(일), h(시), m(분), s(초), w(주)

//2016-01-01부터 6개월 후 < x < 현재에서 365일 전 
GET phones/_search
{
  "query": {
    "range": {
      "date": {
        "gt": "2016-01-01||+6M",
        "lt": "now-365d"
      }
    }
  }
}

출처 : https://esbook.kimjmin.net/

0개의 댓글