Elastic Search (4) QueryDSL & Connect With NestJS

백선호·2021년 9월 29일
0
post-thumbnail

Query DSL

Elasticsearch는 쿼리를 실행하는 데 사용할 수 있는 JSON 스타일 도메인 관련 언어를 제공하는데 이것이 QueryDSL이다. Querydsl은 HQL(Hibernate Query Language) 쿼리를 타입에 안전하게 생성 및 관리할 수 있게 해주는 프레임워크이다. 즉 Querydsl은 자바 코드 기반으로 쿼리를 작성하게 해준다. 몇 가지 기본 예제를 통해 기본 문법을 익히고 NestJS 비즈니스 로직에 적용시켜 보겠다.

데이터 생성

POST tourcompany/_bulk
{"index" : {"_id" : "1"}}
{"name" : "Alfred","phone" : "010-1234-5678","holyday_dest" : "Disneyland","departure_date":"2017/01/20"}
{"index" : {"_id" : "2"}}
{"name" : "Huey","phone" : "010-2222-2222","holyday_dest" : "Disneyland","departure_date" : "2017/01/20"}
{"index" : {"_id" : "3"}}
{"name" : "Naomi","phone" : "010-3333-3333","holyday_dest" : "Hawai","departure_date" : "2017/01/10"}
{"index" : {"_id" : "4"}}
{"name" : "Andra","phone" : "010-6666-7777","holyday_dest" : "BoraBora","departure_date" : "2017/01/11"}
{"index" : {"_id" : "5"}}
{"name" : "Paul","phone" : "010-9999-8888","holyday_dest" : "Hawai","departure_date" : "2017/01/10"}
{"index" : {"_id" : "6"}}
{"name" : "Clin","phone" : "010-5555-4444","holyday_dest" : "Venice","departure_date" : "2017/01/16"}

예제의 사용할 데이터를 생성하겠다. 필자는 mapping을 하지 않고 index를 생성하였다.

from & size

POST /tourcompany/_search
{
  "query": { "match_all": {} },
  "from": 1, 
  "size": 2
}

예제에서의 from은 결과의 1번째 항목부터 보여주며, Default:1이다. size는 결과를 2 개만 불러오며, Default: 10이다.

sort

POST /tourcompany/_search
{
"query": { "match_all": {} },
"sort": { "_id": "desc" } 
}

match_all을 수행하고 결과의 _id 기준으로 내림차순으로 정렬해서 문서를 반환한다.

source

POST /tourcompany/_search
{
  "query": { "match_all": {} },
  "_source": ["name"]
}

전체 소스 문서가 반환되기를 원하지 않으면 _source 내의 일부 필드만 지정하여 결과를 반환할 수 있다.

match & match_pharse

POST /tourcompany/_search
{
  "query": { "match": { "name": "Paul" } }
}

Paul이라는 name의 결과를 반환한다.

POST /tourcompany/_search
{
  "query": { "match_phrase": { "name": "Paul" } }
}

match와 match_pharse의 결과는 동일하지만 만약 { "name": "mile stone" }이었다면, match는 mile 또는 stone과 일치하면 반환하지만 match_pharse는 “mile stonee”이라는 문구가 일치하면 반환한다.

must

POST /tourcompany/_search
{
  "query":{ 
    "bool": {
       "must": [
             { "match": { "name": "Paul" } },
             { "match": { "phone": "010-9999-8888" } }
      ]
    }
  }
}

두 개의 일치 쿼리를 작성하고 name에 "Paul" phone에 "010-9999-8888"을 포함하는 모든 결과를 반환한다.

POST /tourcompany/_search
{
  "query":{ 
    "bool": {
       "must": [{ "match": { "name": "Paul" } }],
        "must_not": [{"match": {"holyday_dest": "Venice"}}]
    }
  }
}

must에 일치하는 쿼리를 작성하고 must_not에는 일치하지 않을 쿼리를 작성한다.

prefix Query

POST /tourcompany/_search
{
  "query": {
    "prefix": {
      "holyday_dest": {
        "value": "di"
      }
    }
  }
}

Prefix Query는 Elastic에서 제공하는 앞 글자 일치 검색 기능이다. 예제는 앞 글자 기준으로 holyday_dest에 "di"가 포함되어 있는 결과를 반환한다.

text & keyword

POST /tourcompany/_search
{
  "query": {
    "prefix": {
      "holyday_dest": {
        "value": "di"
      }
    }
  }
}

POST /tourcompany/_search
{
  "query": {
    "prefix": {
      "holyday_dest.keyword": {
        "value": "Di"
      }
    }
  }
}

Text Type에 대한 검색은 띄어쓰기 기준으로 키워드가 색인된다. 상위 예제에서는 소문자로 검색해야 결괏값이 반환된다. 반면에 Keyword Type은 띄어쓰기를 무시하고 키워드가 색인된다. 상위 예제에서는 대문자로 검색해야 결괏값이 반환된다.

상위 사진의 예제를 보면 "스팀 게임"이라고 검색을 진행했다. Text Type "스팀 게임 추천" Keyword Type은 "스팀 게임 추천"으로 index key가 형성된다.

Fuzzy Query

GET /tourcompany/_search
{
  "query": {
    "fuzzy": {
      "name.keyword": {
        "value": "Pau!",  
        "fuzziness": 1
      }
    }
  }
}

Elastic에서 제공하는 Fuzzy Query를 통한 자동완성이다. Fuzzy Query를 사용하게 되면 편집 거리 알고리즘을 사용하여 오타를 교정하는 검색이 가능하다. 즉 fuzziness 설정값 이하로 글자를 바꾸거나, 넣거나, 빼는 횟수를 측정하여 검색한다. 필자는 fuzziness를 1로 설정해서 1글자에 대해서 교정을 해주었다.

match_pharse_prefix

GET /tourcompany/_search
{
  "query": {
    "match_phrase_prefix": {
      "name": "Pa"
    }
  }
}

Match Phrase Prefix 기본적으로 Text Type에 검색을 하며 앞색인어와 뒷색인어 둘 모두 만족해야만 검색이 되는 형식이다.

ElasticSearch Connect With NestJS


먼저 검색 로직이 구현될 수 있는 module에 elasicsearch의 속성을 적용시켜 준다.
필자는 bool 쿼리를 사용하여 Fuzzy와 Prefix를 혼합하여 쓰는 방식을 선택했고 Should를 사용하여 Fuzzy와 Prefix 중 한 가지라도 조건이 맞으면 결과가 반환된다.



controller를 만들어주고 sevice에 SearchService를 DI시켜주고 로직을 완성하면 된다.

profile
baik9261@gmail.com

0개의 댓글