본문 바로가기
Data/ELK

[2021.05.04] 인턴 +64 Elasticsearch Query DSL 개념 및 사용법

by injekim97 2021. 5. 4.
반응형

[2021.05.04] 인턴 +64  Elasticsearch Query DSL 개념 및 사용법

 

 

 

 

* 해당 게시글은 아래의 document를 참고하여, 중요한 내용을 주황색으로 풀어다 씀

 

 

esbook.kimjmin.net/05-search/5.1-query-dsl

 

5.1 풀 텍스트 쿼리 - Full Text Query

이 문서의 허가되지 않은 무단 복제나 배포 및 출판을 금지합니다. 본 문서의 내용 및 도표 등을 인용하고자 하는 경우 출처를 명시하고 김종민(kimjmin@gmail.com)에게 사용 내용을 알려주시기 바랍

esbook.kimjmin.net

-> Elasticsearch Query DSL document

 

 

 

 

* Elasticsearch Query DSL란?

-> Elasticsearch 는 검색을 위한 쿼리 기능을 제공함

-> 이런 데이터 시스템에서 제공하는 쿼리 기능을 Query DSL (Domain Specific Language) 이라고 말하며, Query DSL 은 모두 json 형식으로 입력해야함.

 

 

-------------------------------------------------------------------------------------------------------------

자, 이제 명령어들에 대해 실습을 하기 위해 셋팅을 해보자.

-> Linux에서, elasticsearch 와 kibana를 실행한 후, 

-  ssh -i elk_key.pem ubuntu@52.188.20.167

-  cd /usr/share/elasticsearch/bin/        ->    ./elasticsearch

-  cd /usr/share/kibana/bin/        ->    ./kibana

 

-> 52.188.20.167:5601주소로 들어가서, dev tools에서 실습을 해보자.(위의 document site refer)

-> 이렇게 실습 준비가 완료되었다. 

-> 이제 명령어를 하나씩 입력해서 실습해보자.

------------------------------------------------------------------------------------------------------------------------

실습하기 앞서, 데이터 삽입

-> 우선 명령어를 실습하기 전에, 데이터가 없기 때문에 위의 document에 있는 데이터를 삽입 후 진행하겠다.

 

 

POST study_query_dsl/_bulk
{"index": {"_id":1}}
{"message":"The quick brown fox"}
{"index": {"_id":2}}
{"message":"The quick brown fox jumps over the lazy dog"}
{"index": {"_id":3}}
{"message":"The quick brown fox jumps over the quick dog"}
{"index": {"_id":4}}
{"message":"Brown fox brown dog"}
{"index": {"_id":5}}
{"message":"Lazy jumping dog"}

-> 위의 code를 복붙 후 dev tools에 복붙 후에 컨트롤 + A를 누른후 재생버튼 클릭

-> 데이터가 추가 되었다. 

 

 

-> 삽입된 데이터를 확인하려면 GET 인덱스명/_search로 확인해보자.

 

 

DELETE study_query_dsl

-> 인덱스 삭제하는 명령어

----------------------------------------------------------------------------------------------------

이제 명령어를 사용해보자.

 

 

 

 

5.1 풀 텍스트 쿼리 - Full Text Query

* match_all (두 가지 명령어로 사용 가능 - 결과 값 동일)

-> 해당 명령어는 전부다 출력함.

-> match_all 은 해당 인덱스의 모든 도큐먼트를 검색하는 쿼리

 

GET study_query_dsl/_search

GET study_query_dsl/_search
{
"query":{
  "match_all":{ }
  }
}

 

 

 

 

* match

-> 해당 명령어는 "message"인 필드 값 안에 dog라는 문장을 검색하는 명령어

GET study_query_dsl/_search
{
  "query": {
    "match": {
      "message": "dog"
    }
  }
}

-> dog가 포함된 총 4개의 도큐먼트가 검색 결과로 나타남

 

 

 

-> "message": "quick dog" 에서 스페이스(공백)기준으로 단어를 분리함. (즉 여기선, quick , dog를 찾는 것임)

-> match 검색에 여러 개의 검색어를 집어넣게 되면 디폴트로 OR 조건으로 검색

 

 

 

 

* match (or 조건 -> and 조건으로 변경하는 방법)

->  "message" 필드 안에,  "operator": "and" 를 추가하게 되면, quick dog 즉 quick 하고, dog를 두가지 이상 포함한 message만 출력한다.

GET study_query_dsl/_search
{
  "query": {
    "match": {
      "message": {
        "query": "quick dog",
        "operator": "and"
      }
    }
  }
}

 

 

 

* match_phrase

-> "quick dog" 라는 구문을 공백을 포함해 정확히 일치하는 내용을 검색하기 위한 명령어

-> 입력된 검색어를 순서까지 고려하여 검색을 수행

GET study_query_dsl/_search
{
  "query": {
    "match_phrase": {
      "message": "lazy dog"
    }
  }
}

-> "lazy dog" 라는 정확한 문장이 포함된 것이 1개만 검색됨.

 

 

 

-> slop 이라는 옵션을 이용하여 slop에 지정된 값 만큼 단어 사이에 다른 검색어가 끼어드는 것을 허용(SQL : %)

 

 

 

* query_string

-> 구문 검색을 할 때는, 검색할 구문을 쌍다옴표 \(역슬래쉬)" 안에 넣습니다.

-> "Lazy jumping dog" 와 "quick dog" 값을 포함하는 값을 출력함

-> jumping lazy 를 포함하는 단어와, quick dog 단어를 포함하는 것을 출력하기 때문(or)

 

 

 

------------------------------------------------------------------------------------------------------------------------------

Bool 복합 쿼리 - Bool Query

-> 여러 쿼리를 조합하기 위해서는 상위에 bool 쿼리를 사용하고 그 안에 다른 쿼리들을 넣는 식으로 사용이 가능

 

 

bool 쿼리는 다음의 4개의 인자를 가지고 있으며 그 인자 안에 다른 쿼리들을 배열로 넣는 방식으로 동작

-> must : 쿼리가 참인 도큐먼트들을 검색 

-> must_not : 쿼리가 거짓인 도큐먼트들을 검색 

-> should : 검색 결과 중 이 쿼리에 해당하는 도큐먼트의 점수를 높임.

-> filter : 쿼리가 참인 도큐먼트를 검색하지만 스코어를 계산하지 않음. (must 보다 검색 속도가 빠름, 캐싱 가능)

 

 

 

 

* must

-> 쿼리가 참인 경우에 검색함.

-> 아래의 사진의 소스코드를 보면, "message"필드에, 문장 quick 과 lazy dog를 가지는 문장을 검색

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

-> 즉, "quick"과 "lazy dog"가 포함된 모든 문서를 검색하는 쿼리

 

 

 

* must_not

-> 쿼리가 거짓인 도큐먼트들을 검색

-> "quick" , "lazy dog"가 하나도 포함되지 않은 문서를 검색

 

GET study_query_dsl/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "message": "quick"
          }
        },
        {
          "match_phrase": {
            "message": "lazy dog"
          }
        }
      ]
    }
  }
}

여기서, 알아야 될 것은 "lazy dog"은 한문장으로 취급함.

-> 파란색으로 밑줄 친 "message" : "Lazy jumping dog"도 한문장이기 때문에 출력이 됨

 

 

 

* bool 쿼리의 must, should 등은 표준 SQL의 AND, OR 등과 유사하지만 정확히 같지는 않습니다.

표준 SQL : AND, OR 조건 들은 2개의 조건값에 대한 이항 연산자

* Elasticsearch : must, must_not, should 등은 내부에 있는 각각의 쿼리들에 대해 이 쿼리는 참 또는 거짓으로 적용하는 단항 연산자

 

 

 

 

(A or B) and (not C) 에 대한 쿼리를 하려면

-> elasticsearch의 경우 다음처럼 A와 B의 OR 조건의 match 쿼리로 하여 must 안에 넣고

-> C를 must_not에 넣으면 됨

----------------------------------------------------------------------------------------------------------------------

5.3 정확도 - Relevancy

 

 

* 스코어 (score) 점수

-> 각 검색 결과의 _score 항목에 스코어 점수가 표시되고 점수가 높은 결과부터 나타납니다.

-> 그리고 상단의 max_score 전체 결과 중에서 가장 높은 점수가 표시

 

-> 검색 결과에서 lazy 를 포함하고 있는 2개의 도큐먼트 들이 나타났지만 ,

-> "The quick brown fox jumps over the lazy dog" 보다 길이가 짧은 "Lazy jumping dog" 가 점수가 더 높음

-> 즉, 문장이 짧을 수록 좋은 점수를 가질 수 있음.

 

 

--------------------------------------------------------------------------------------------------------

5.4 Bool : Should

 

* Should

-> 검색 점수를 조정하기 위해 사용

-> fox만 포함하고 있던 "The quick brown fox" 는 점수가 "_score" : 0.2953

-> lazy를 함께 포함하고 있는 "The quick brown fox jumps over the lazy dog" 는 점수가 "_score" : 0.9395

-> 즉, fox 검색 결과 중 lazy를 포함한 결과에 점수를 더 높게 줌.

 

 

 

 

<should 에 match_phrase 사용하기>

-> 쇼핑몰 상품 검색 같은 사례에서는 보통 검색어로 입력된 단어가 하나라도 포함된 결과들은 모두 가져오도록 되어 있을 것입니다.

 

-> 이 때 검색 결과 중에서 입력한 검색어 전체 문장이 정확히 일치하는 결과를 맨 상위에 위치시키면 다른 결과들을 누락시키지 않으면서 사용자가 정확하게 원하는 수준 높은 품질의 결과를 제공할 수 있을 것입니다.

 

-> 다음은 lazy 또는 dog 중 하나라 포함된 도큐먼트를 모두 검색하면서 그 중에 "lazy dog" 구문을 정확히 포함하는 결과들을 가장 상위로 가져옵니다.

 

-> must 안에 match 쿼리로 lazy 또는 dog가 포함된 모든 도큐먼트를 검색하고 should 안에 match_phrase 쿼리를 써서 스코어 점수를 높입니다.

 

-> lazy , dog 를 검색하면서, "lazy dog" 구문을 정확히 포함하는 결과를 가장 상위로 가져옴.

 

* EX) 쇼핑몰에서 "스키 장갑" 단어로 검색했을 때 (should 와 match_phrase를 응용) ★

1. 가장 상단에 스키 장갑을 표시

2. 스키 용품들과 각종 장갑들을 모두 가져옴

* slop:1 옵션 추가시, 스키 ________ 장갑 

-> "스키 보드 장갑", "스키 벙어리 장갑" 같이 스키와 장갑 사이에 다른 값이 들어간 결과에도 가중치를 부여

 

 

 

 

-------------------------------------------------------------------------------------------------------------------------

5.5 정확값 쿼리 - Exact Value Query

 

* bool : filter
-> bool쿼리의 filter 안에 하위 쿼리를 사용하면 스코어에 영향 X

 

 

<첫 번째 예시>

-> 첫 번째는 match 쿼리로 fox 를 검색했을 때 4개의 도큐먼트가 검색되었고,

-> 가장 높은 스코어는 "_score" : 0.2953231입니다.

 

 

<두 번째 예시>

-> 두 번째는 검색에 match 쿼리로 quick 을 추가했을 때 3개의 도큐먼트가 검색

-> 가장 높은 스코어는 "_score" : 0.8979 입니다.

 

 

 

 

<세 번째 예시>

-> 세 번째는 첫번째의 검색에 filter 구문 안에 quick 을 추가했는데 3개의 도큐먼트가 검색됨

-> 가장 높은 스코어는 첫번째 쿼리와 같은 "_score" : 0.2953 입니다.

 

* filter는 검색에 조건을 추가하지만, 스코어에는 영향 X 사용

-> 주로, 쇼핑몰에서 검색어로 정확도가 높은 상품명을 검색하면서 생산 업체를 다시 필터링 하는 등의 용도로 사용

 

 

 

 

 

<filter 내부에서 must_not 과 같은 다른 bool 쿼리를 포함하려면?>

-> filter 내부에 bool 쿼리를 먼저 넣고 그 안에 다시 must_not 을 넣은 후,

-> fox 를 포함하면서 dog 는 포함하지 않는 도큐먼트를 검색하는 쿼리

* dog 를 제외하는 must_not 쿼리가 filter 안에 있기 때문에 스코어는 fox 에만 영향을 받습니다.

 

 

 

 

 

* keyword

-> 문자열 데이터는 keyword 형식으로 저장하여 정확값 검색이 가능

-> message 필드값이 "Brown fox brown dog" 문자열과 공백, 대소문자까지 정확히 일치하는 데이터만을 출력

* keyword 필드는 스코어를 계산하지 않고 정확값의 일치 여부만을 따지기 때문에, 스코어가 "_score" : 0.0 출력

* 스코어를 계산하지 않기 때문에 keyword 값을 검색 할 때는 filter 구문 안에 넣음

 

* filter 안에 넣은 검색 조건들은 스코어를 계산하지 않지만 캐싱이 되기 때문에 쿼리가 더 가볍고 빠르게 실행됨

-> keyword,range (스코어 계산이 필요X)은 모두 filter 안에 넣어서 실행하는 것이 좋음.

--------------------------------------------------------------------------------------------------------------------------

5.6 범위 쿼리 - Range Query

 

* Elasticsearch는 숫자날짜 형식들의 저장이 가능

-> 숫자, 날짜 형식은 range 쿼리를 이용해서 검색

 

 

 

우선, range 예제 실습을 위해 새로운 인덱스에 데이터를 넣어보자.

POST phones/_bulk
{"index":{"_id":1}}
{"model":"Samsung GalaxyS 5","price":475,"date":"2014-02-24"}
{"index":{"_id":2}}
{"model":"Samsung GalaxyS 6","price":795,"date":"2015-03-15"}
{"index":{"_id":3}}
{"model":"Samsung GalaxyS 7","price":859,"date":"2016-02-21"}
{"index":{"_id":4}}
{"model":"Samsung GalaxyS 8","price":959,"date":"2017-03-29"}
{"index":{"_id":5}}
{"model":"Samsung GalaxyS 9","price":1059,"date":"2018-02-25"}

 

 

* POST range_study_dsl/_bulk

-> POST 인덱스/_bulk 명령어로 해당 인덱스를 만들어, 값을 추가함

 

* GET range_study_dsl/_search

-> 저장한 인덱스 값을 전체 출력

 

 

 

 

* range

-> { <필드명>: { <파라메터>:<값> } }

 

 

range 쿼리 파라메터는 아래의 4가지가 있습니다.

1. gte (Greater-than or equal to) - 이상 (같거나 큼)

2. gt (Greater-than) – 초과 (큼)

3. lte (Less-than or equal to) - 이하 (같거나 작음)

4. lt (Less-than) - 미만 (작음)

 

 

 

EX)  price 필드 값이 700 이상, 900 미만인 데이터를 검색하는 쿼리를 해보자.

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

 

 

 

 

 

날짜 검색

-> Elasticsearch 에서 날짜 값은 2016-01-01 또는 2016-01-01T10:15:30

 

 

EX) date 필드의 날짜가 2016년 1월 1일 이후인 도큐먼트들을 검색하는 쿼리입니다.

GET range_study_dsl/_search
{
  "query": {
    "range": {
      "date": {
        "gt": "2016-01-01"
      }
    }
  }
}

 

 

 

 

 

 

 

<날짜 포맷을 다르게 하고 싶을 땐?>

-> || 을 사용해서 여러 값의 입력이 가능

-> 위의 사진은 date 필드의 값이 2015년 12월 31일 ~ 2018년 이전 사이에 있는 값들을 검색하는 쿼리

 

 

<시,분,초 검색>

-> 날짜를 검색 할 때는 검색하는 현재 시간을 가져오는 예약어 now와 y(년), M(월), d(일), h(시), m(분), s(초), w(주) 

-> 다음은 date의 값이 2016년 1월 1일에서 6개월 후 ~ 오늘보다 365일 전 데이터를 가져오는 쿼리

 

* 인덱스의 전체 도큐먼트 중 2016년 1월 1일에 6개월을 더한 2016-06-01과 검색을 실행한 2019년 9월 3일 보다 1년 전인 2018-09-03 사이의 값인 "date" : "2017-03-29", "date" : "2018-02-25" 두 개의 결과가 출력

반응형

댓글