[2021.05.04] 인턴 +64 Elasticsearch Query DSL 개념 및 사용법
* 해당 게시글은 아래의 document를 참고하여, 중요한 내용을 주황색으로 풀어다 씀
esbook.kimjmin.net/05-search/5.1-query-dsl
-> 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" 두 개의 결과가 출력
'Data > ELK' 카테고리의 다른 글
[2021.05.14] 인턴 +74 AWS Linux(Ubuntu:20.04) ELK 설치 및 실행방법 (0) | 2021.05.14 |
---|---|
[2021.05.06] 인턴 +66 Query DSL을 통해 원하는 필드 값만 추출 하는 방법 (0) | 2021.05.06 |
[2021.04.16] 인턴 +46 Linux(Ubuntu18.04) - Apache log analysis (geoip 사용) (0) | 2021.04.16 |
[2021.04.14] 인턴 +44 Linux(Ubuntu18.04) - ELK 설치(MySQL 연동 포함) & Virtual Machine (Azure) (0) | 2021.04.14 |
[2021.04.06] 인턴 +36 Azure에서 ELK 사용하기(가상머신X) (0) | 2021.04.06 |
댓글