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 |
각 샤드별로 얼마나 시간을 소요했나? | 스코어가 어떻게 나왔는기? |