Search

[엘라스틱 서치 실무 가이드] 4장 데이터 검색

4.1 검색 API

4.1.1 검색 질의 표현 방식
URI 검색 : 루씬에서 사용하던 전통적인 방식
Request Body 검색 : RESTful API를 이용해 Request Body에 조건을 표기하는 표기법
4.1.2 URI 검색
파라미터를 Key=Value 방식으로 전달. 복잡한 쿼리는 불가
꿀만 사용하고 되도록이면 Request Body 검색 사용
_source _exclued : 제외할 컬럼
파라미터
기본값
설명
q
-
검색을 수행할 쿼리 문자열 조건을 지정
df
-
쿼리에 검색을 수행할 필드가 지정되지 않았을 경우 기본값으로 검색할 필드를 지정
analyzer
검색 대상 필드에 설정된 형태소 분석기
쿼리 문자열 형태소 분석할 때 사용할 형태소 분석기를 지정
analyze_wildcard
false
접두어/와일드카드 검색 활성화 여부 지정
default_operator
OR
두 개 이상의 검색 조건이 쿼리 문자열에 포함된 경우 검색 조건 연산자를 설정
_source
true
검색 결과에 문서 본문 포함 여부를 지정
sort
-
검색 결과의 정렬 기준 필드를 지정
from
-
검색을 시작할 문서의 위치를 설정
size
-
반환할 검새 결과 개수를 설정
4.1.3 Request Body 검색
JSON 형태의 표현을 사용하여 엘라스틱에서 지원하는 Query DSL 문법을 사용

4.2 query dsl 이해하기

4.2.1 query dsl 구조
{ "size" : "리턴 받을 결과의 개수 지정 " "from" : "몇 번째 문서부터 가져올지 지정" "timeout" : "검색을 요청해서 결과를 받는 데까지 걸리는 시간." " 너무 짧게 잡으면 전체 샤드에서가 아닌 timeout을 넘기지 않는 문서만 출력됨." "기본값은 무한대" "_source" : "검색 시 출력하고 싶은 필드 지정. 제외도 가능" "query" : "검색 조건문" "aggs" : "통계 및 집계 데이터" "sort" : "정렬"
JavaScript
복사
{ "took" : "쿼리 실행 시간" "timed_out" : "쿼리 시간이 초과할 경우" "_shards" : { "total" : "쿼리를 요청한 전체 샤드의 개수" "successful" : "성공적으로 응답한 샤드의 개수" "failed" : "검색 요청에 실패한 샤드의 개수" } "hits" : { "total" : "전체 매칭된 문서의 개수" "max_score" : "스코어 중 가장 높은 값" "hits" : [] "문서 정보와 스코어" } }
JavaScript
복사
4.2.2 query dsl 쿼리와 필터
쿼리 컨텍스트
필터 컨텍스트
용도
전문 검색 시 사용
조건 검색 시 사용(Yes/No)
특징
분석기에 의해 분석이 수행됨
연관성 점수 계산
분석 과정이 루씬 레벨에서 이루어지므로 상대적으로 느립니다. 이는 Yes/No로 간단히 판별될 수 있습니다.
연관성 점수 계산을 하지 않습니다.
엘라스틱 서치 레벨에서 처리 가능하므로 상대적으로 빠릅니다.
| 사용 예시 | 문장 분석 | 일치 여부, 포함 여부 |
쿼리 컨텍스트
문서가 쿼리와 얼마나 유사한지를 스코어로 계산합니다.
질의가 요청될 때마다 엘라스틱서치는 내부의 루씬을 이용해 계산을 수행합니다(결과는 캐싱되지 않습니다).
일반적으로 전문 검색에 많이 사용됩니다.
결과가 캐싱되지 않고 디스크 연산이 수행되므로 상대적으로 느립니다.
필터 컨텍스트
쿼리의 조건과 문서가 일치하는지(Yes/No)를 구분합니다.
별도로 스코어를 계산하지 않고 단순히 매칭 여부만 검사합니다.
엘라스틱서치는 자주 사용되는 필터의 결과를 내부적으로 캐싱합니다.
기본적으로 메모리 연산을 수행하므로 상대적으로 빠릅니다.
4.2.3 query dsl의 주요 파라미터
multi index 검색
GET <인덱스 명1>,<인덱스 명2>/_search // 여러 인덱스를 한번에 쿼리 가능. 공통적으로 가지고 있는 필드가 있어야 됨 GET 인덱스명-*/_search // 인덱스명으로 시작하는 여러 인덱스 한번에 조회 가능
JavaScript
복사
쿼리 결과 페이징
GET <인덱스 명1>/_search { "from" : 0, // 시작할 부분 "size" : 10, // 가져올 문서 개수 "query" : {} }
JavaScript
복사
관계형 데이터와는 다르게 페이징된 문서만 가져오는 것이 아닌 대상 전체를 읽어오기 때문에 페이지 번호가 높아질수록 쿼리 비용도 높아진다
쿼리 결과 정렬
여러 개의 필드로 정렬 가능
GET <인덱스 명1>/_search { "sort" : { "createDt" : { "order" : "asc" } } }
JavaScript
복사
_source 필드 필터링
GET <인덱스 명1>/_search { "_source" : [ "title", "createDt" // 조회 시 해당 두 필드만 검색 결과에 나옴 ] }
JavaScript
복사
범위 검색
숫자나 날짜 데이터의 경우 범위로 질의 가능
GET <인덱스 명1>/_search { "query" :{ "range" : { "createDt" : { "gte" : "2016", "lte" : "2017" } } } }
JavaScript
복사
operator 설정
문장이 들어올 경우 기본적으로 OR 연산
GET movie_search/_search { "query" : { "match" : { "movieNm" : { "query" : "자전차왕 엄복동", "operator" "and" } } } }
Java
복사
minimum_should_match 설정
OR 연산시 사용 가능한 옵션
텀의 개수가 몇 개 이상 매칭될 때만 검색
예시의 경우 AND 연산과 동일한 결과를 낼 수 있음
GET movie_search/_search { "query" : { "match" : { "movieNm" : { "query" : "자전차왕 엄복동", "minimum_should_match":"2" } } } }
Java
복사
fuzziness 설정
유사한 값을 찾는 Fuzzy Query로 변경
오차범위 값으로 0, 1, 2, AUTO 로 설정 가능
한글보다는 영어에서 유용함
GET movie_search/_search { "query" : { "match" : { "movieNm" : { "query" : "fli high", "fuzziness":"1" } } } }
Java
복사
boost 설정
예제는 한글 영화 제목에 가중치를 더 줌
GET movie_search/_search { "query" : { "multi_match" : { "query" : "Fly", "fields":["movieNm^3", "movieNmEn"] } } }
Java
복사

4.3 query dsl의 주요 쿼리

4.3.1 Match All Query
모든 문서를 검색하는 쿼리
4.3.2 Match Query
검색어를 형태소 분석을 통해 텀으로 분리한 후 이 텀들을 이용해 검색 질의
검색어가 분석돼야 할 경우
별도 operator가 없을 경우 OR 연산
4.3.3 Multi Match Query
여러 개의 필드를 대상으로 검색할 때
GET movie_search/_search { "query" : { "multi_match" : { "query" : "Fly", "fields":["movieNm", "movieNmEn"] } } }
Java
복사
4.3.4 Term Query
POST movie_search/_search { "query" : { "term" : { "genreAlt" : "코미디" } } }
JSON
복사
분석 작업을 수행하지 않고 검색어에 대한 Term을 찾는 쿼리
keyword 데이터 타입을 사용하는 필드를 검색하려면 term query 사용
분석 작업이 없기 때문에 그대로를 찾으므로 정확한 검색어를 질의해야함(대소문자 구분 등)
4.3.5 Bool Query
"query": {"bool": {"must": [], "must_not": [], "should": [], "filter": []}} POST movie_search/_search { "query": { "bool": { "must": [ { "term": { "repGenreNm": "코미디" } }, { "match": { "repNationNm": "한국" } } ], "must_not": [ { "match": { "typeNm": "단편" } } ] } } }
JSON
복사
엘라스틱서치에서도 여러 개의 쿼리를 조합해서 사용하고 싶을 때 사용
must : 반드시 조건에 만족
must_not : 조건에 만족하지 않는 문서
should : 여러 조건 중 하나 이상
filter : 조건을 포함하고 있는 문서를 출력. 사용시 스코어별로 정렬되지 않음
여러 개의 옵션을 조합하여 복잡한 쿼리 가능
4.3.6 Query String
내장된 쿼리 분석기를 이용하는 질의
GET movie_search/_search { "query" : { "query_string" : { "default_field" : "movieNm", "query":"(가정) AND (어린이날)" } } }
Java
복사
이 부분에 대한 설명은 약한듯.

Simple Query String Query

simple_query_string 쿼리는 query_string 쿼리와 비슷하지만 몇 가지 중요한 차이점이 있습니다. 이 쿼리는 사용하기 편리하며, 쿼리 구문 오류를 허용하지 않습니다.
예시
GET movie_search/_search { "query": { "simple_query_string": { "default_field": "movieNm", "query": "+가정 +어린이날" } } }
Java
복사
위 예시에서 default_field는 기본 검색 필드를 지정하고, query는 검색어를 포함합니다. + 기호를 사용해 필수 포함 단어를 지정할 수 있습니다.
주요 특징
사용하기 편리합니다.
구문 오류를 허용하지 않아, 잘못된 쿼리 구문이 있어도 무시하고 검색을 진행합니다.
제한된 구문을 지원하므로 유연성은 떨어지지만, 안전하게 사용할 수 있습니다.
비교
특징
Query String Query
Simple Query String Query
구문 복잡성
높음
낮음
오류 허용 여부
허용하지 않음
허용함
유연성
높음
낮음
주요 사용 용도
복잡한 검색 조건이 필요한 경우
간단한 검색 조건이 필요한 경우
4.3.7 Prefix Query
역색인된 텀은 사전순으로 정렬되고 Prefix Query는 저장된 텀들을 스캔해서 일치하는 텀을 찾음
접두어가 있는 모든 문서를 검색
텀중에 일치하는 문서를 찾음
POST movie_search/_search { "query": { "prefix": { "movieNm": "자전차" } } }
JSON
복사
4.3.8 Exists Query
필드 데이터가 존재하는 문서만 찾고 싶을 때
GET movie_search/_search { "query" : { "exists" : { "field" : "movieNm" } } }
Java
복사
4.3.9 Wildcard Query
검색어가 와일드카드와 일치하는 구문을 찾음. 입력된 검색어는 형태소 분석이 이뤄지지 않음
* : 문자 길이와 상관없이 와일드카드와 일치하는 모든 문서를 찾는다
? : 지정된 위치의 한 글자가 다른 경우의 문서를 찾는다
POST movie_search/_search { "query": { "wildcard": { "typeNm": "장" } } }
JSON
복사
와일드카드를 사용할 경우, 단어의 첫 글자로는 절대 사용해서는 안 됩니다. 첫 글자로 와일드카드를 사용하면, 색인된 전체 문서를 검색해야 하므로 부적절한 상황이 발생할 수 있습니다.
4.3.10 Nested Query
분산 시스템에서 SQL의 '조인'을 수행하려면 많은 비용이 들 수 있습니다. 왜냐하면 샤드가 얼마나 늘어날지 모르는 상황에서 모든 샤드를 찾아봐야 하기 때문입니다.
그러나 업무를 하다 보면 문서 간의 부모/자식 관계를 나타내는 경우가 자주 있을 것입니다.
이런 경우를 위해 엘라스틱서치에서는 분산 데이터 환경에서도 SQL '조인'과 비슷한 작업을 할 수 있는 Nested Query를 제공.
Nested Query는 Nested 데이터 타입의 필드를 찾을 때 사용.
Nested 데이터 타입은 문서 안에 다른 문서가 있을 때 사용.
'path' 옵션으로 중첩된 필드를 지정하고, 'query' 옵션에 Nested 필드 검색에 사용할 쿼리를 입력합니다.
PUT movie_nested/_doc/1 { "movieCd" : "20184623", "movieNm": "바람난 아내들2", "movieNmEn" : "", "prdYear" : "2018", "openDt" : "", "typeNm": "장편", "prdStatNm": "개봉예정", "nationAlt": "한국", "genreAlt": "멜로/로맨스", "repNationNm" : "한국", "repGenreNm": "멜로/로맨스", "companies" : [ { "companyCd" : "20173401", "companyNm" : "(주) 케이피에이 기획" } ] } # child에 저장된 companyCd를 검색 GET movie_nested/_search { "query": { "bool": { "must": [ { "term": { "repGenreNm": "멜로/로맨스", "nested": { "path": "companies", "query": { "bool": { "must": [ { "term": { "companies.companyCd": "20173401" } } ] } } } } } ] } } }
JSON
복사
이 쿼리는 repGenreNm 필드가 "멜로/로맨스"인 문서를 찾고, 그 문서 내의 중첩된 companies 객체에서 companyCd가 "20173401"인 문서를 검색
엘라스틱서치는 성능을 위해 부모 문서와 자식 문서를 같은 샤드에 저장.
이렇게 하면 네트워크 비용을 크게 줄일 수 있습니다.
그러나 특정 부모 문서에 포함된 자식 문서가 너무 커지면 샤드의 크기가 균등하게 분배되지 않는 문제가 발생할 수 있습니다. 그래서 데이터 스키마를 설계할 때 주의해야 합니다.

4.4 부가적인 API

4.4.1 효율적인 검색을 위한 환경 설정
검색 요청이 발생할 때:
1.
엘라스틱서치는 대량의 데이터를 처리하기 위해 분산 처리함 모든 샤드에 검색 요청을 브로드캐스팅하여 전달하고 대기합니다.
2.
각 샤드는 자신이 가지고 있는 데이터를 기준으로 검색을 수행하고 그 결과를 반환합니다.
3.
모든 샤드로부터 검색 결과가 도착하면, 도착한 모든 결과를 조합하여 최종 질의 결과를 출력합니다.
동적 분배 방식의 샤드 선택
검색 요청을 수행하는 스레드 풀의 크기 등을 고려하여 최적의 샤드를 동적으로 결정하는 방식입니다.
기본적으로는 라운드 로빈을 사용합니다.
PUT _cluster/settings { "transient" : { "cluster.routing.use_adaptive_replica_selection" : true } }
Java
복사
글로벌 타임아웃 설정
무거운 쿼리가 계속 실행되는 것을 방지합니다.
기본 값은 -1초(무제한)입니다.
PUT _cluster/settings { "transient" : { "search.default_search_timeout": "1s" } }
Java
복사
4.4.2 Search Shards API
검색 시 수행되는 노드 및 샤드에 대한 정보를 확인
질의를 최적화하거나 질의가 정상적으로 수행되지 않을 때 문제를 해결하는 데 유용
GET movie_search/_search_shards
Java
복사
response
4.4.3 Multi Search API
요청을 한번에 해서 데이터를 요청해서 요청 횟수를 줄임
GET _msearch {"index" : "movie_auto"} {"query" : {"match_all" : {}}, "from" : 0, "size" : 10} {"index" : "movie_auto"} {"query" : {"match_all" : {}}, "from" : 0, "size" : 10}
Java
복사
4.4.4 Count API
문서 검색 개수를 가져오는 API
POST movie:_search/_count?q=prdYear:2017
POST movie_search/_count "query" : {"query_string" : {"default_field" : "prdYear", "query" : "2017"}}
JSON
복사
4.4.5 Validate API
쿼리 유효성 검사
rewrite=true 파라미터 : 자세한 정보를 알려줌
GET movie_search/_validate/?rewrite=true { 쿼리 }
Java
복사
4.4.6 Explain API
스코어가 어떻게 계산되었는지 관련 정보를 리턴
특정 문서가 잘 검색되지 않을 때 디버깅 정보로 유용
GET movie_search/_doc/8/_explain { 쿼리 }
Java
복사
4.4.7 Profile API
쿼리 수행 계획과 각 수행 계획별로 수행된 시간을 돌려주는 API
성능을 튜닝하거나 디버깅할 때 유용하게 활용
결과가 매우 방대함. 여러 샤드에 걸쳐 검색되는 쿼리의 경우 더욱 더 길어져 확인하기 힘듬
샤드별 프로파일 정보를 제공
Profile API
Explain API
각 샤드별로 얼마나 시간을 소요했나?
스코어가 어떻게 나왔는기?