11. Query DSL 구조 및 파라미터
엘라스틱서치로 검색 질의를 요청할 때는 Request Body 검색과 URI 검색 모두 _search API를 이용해 검색을 질의합니다. 하지만 Query DSL(JSON 구조 기반)을 이용하면 여러 개의 질의를 조합하거나 질의 결과에 대해 다시 검색을 수행하는 등 기존의 URI 검색보다 강력한 검색이 가능해집니다.
1. Query DSL 쿼리의 구조
# 요청 JSON 구조
{
"size": # 리턴받는 결과의 개수 (기본값 : 10)
"from": # 몇 번째 문서부터 가져올지 지정 (기본값 : 0)
"timeout": # 검색을 요청해서 결과를 받는 데까지 걸리는 시간
너무 짧게 잡으면 전체 샤드에서 timeout을 넘기지 않은 문서만 결과로 출력하기에
상황에 따라 결과의 일부만 나올 수 있음 (기본값 : 무한대)
"_source": {} # 검색 시 필요한 필드만 출력하고 싶을 때 사용
"query": {} # 검색 조건문이 들어가야 하는 공간
"aggs": {} # 통계 및 집계 데이터를 사용할 때 사용하는 공간
"sort": {} # 문서 결과를 어떻게 출력할지에 대한 조건을 사용하는 공간
}
# 응답 JSON 구조
{
"took": # 쿼리 실행 시간
"timed_out": # 쿼리 시간이 초과할 경우를 나타냄
"_shards" : {
"total": # 쿼리를 요청한 전체 샤드의 개수
"successful": # 성공적으로 응답한 샤드의 개수
"failed": # 실패한 샤드의 개수
},
"hits": {
"total": # 검색어에 매칭된 문서의 전체 개수
"max_score": # 일치하는 문서의 스코어 값 중 가장 높은 값
"hits": [] # 각 문서 정보와 스코어 값
}
}
2. Query DSL 쿼리와 필터
쿼리 컨텍스트 | 필터 컨텍스트 | |
용도 | 전문 검색 시 사용 | 조건 검색 시 사용(예: Yes/No) |
특징 | 분석기에 의해 분석이 수행됨. 연관성 관련 Score 계산. 루씬 레벨에서 분석 과정을 거처야 하므로 상대적으로 느림. |
Yes/No로 단순 판별 가능 연관성 관련 계산을 하지 않음. 엘라스틱서치 레벨에서 처리가 가능하므로 상대적으로 빠름. |
사용 예 | "Harry Potter" 같은 문장 분석 | "create_year" 필드의 값이 2018년인지 여부 "status" 필드에 'use'라는 코드 포함 여부 |
# 쿼리 컨텍스트
POST movie_search/_search
{
"query": {
"match": {
"movieNm": "기묘한 가족"
}
}
}
# 필터 컨텍스트
POST movie_search/_search
{
"query": {
"bool": {
"must": [
{
"match_all": {}
}
],
"filter": {
"term": {
"repGenreNm": "다큐멘터리"
}
}
}
}
}
3. Query DSL 주요 파라미터
1) Multi Index 검색
POST movie_search,movie_auto/_search # ","를 이용해 다수의 인덱스명 입력
{
...
}
POST /log-2021-*/_search # 검색 요청 시 인덱스 이름을 지정할 때 "*" 와일드카드 사용
{
...
}
2) 쿼리 결과 페이징
# 첫 번째 페이지 요청
POST movie_search/_search
{
"from": 0,
"size": 5,
"query": {
"term": {
"repNationNm": "한국"
}
}
}
# 두 번째 페이지 요청
POST movie_search/_search
{
"from": 5,
"size": 5,
"query": {
"term": {
"repNationNm": "한국"
}
}
}
엘라스틱서치는 설정된 페이지를 제공하기 위해 전체를 읽어 사이즈만큼 필터링해서 제공하는 구조이기 때문에 페이지 번호가 높아질수록 쿼리 비용은 덩달아 높아질 수밖에 없다는 점에 주의해야 합니다.
3) 쿼리 결과 정렬
POST movie_search/_search
{
"query": {
"term": {
"repNationNm" : "한국"
}
},
"sort" :{
"prdtYear": {
"order": "asc"
},
"_score": {
"order": "desc"
}
}
}
4) _source 필드 필터링
# _source에 검색 결과에 포함하고 싶은 필드 지정
POST movie_search/_search
{
"_source": [
"movieNm"
],
"query": {
"term": {
"repNationNm" : "한국"
}
}
}
5) 범위 검색
# lt : <
# gt : >
# lte : <=
# gte : >=
POST movie_search/_search
{
"query": {
"range": {
"prdtYear": {
"gte": "2016",
"lte": "2017"
}
}
}
}
6) operator 설정
명시적으로 "and"나 "or" 연산자를 지정합니다. operator 파라미터가 생략된 경우에는 기본적으로 텀과 텀에 OR 연산을 적용합니다.
POST movie_search/_search
{
"query": {
"match": {
"movieNm": {
"query": "자전차왕 엄복동",
"operator": "and" # 생략 시 "자전차왕" or "엄복동" 들어있는 모든 문서 검색
}
}
}
}
7) minimum_should_match
텀의 개수가 몇 개 이상 매칭될 때만 검색 결과로 나오게 할 경우에 사용합니다. 아래 예는 텀의 개수와 minimum_should_match 개수가 일치하기에 AND 연산과 동일한 효과를 낼 수 있습니다.
POST movie_search/_search
{
"query": {
"match": {
"movieNm": {
"query": "자전차왕 엄복동",
"minimum_should_match": 2
}
}
}
}
8) fuzziness
단순히 같은 값을 찾는 Match Query를 유사한 값을 찾는 Fuzzy Query로 변경할 수 있습니다. 이는 레벤슈타인(Levenshtein) 편집 거리 알고리즘을 기반으로 문서의 필드 값을 여러 번 변경하는 방식으로 동작합니다.
예를 들어, 편집 거리의 수를 2로 설정한다면 오차범위가 두 글자 이하인 검색 결과까지 포함해서 결과로 출력합니다. 오차범위 값으로 0, 1, 2, AUTO로 총 4자기 값을 사용할 수 있는데, 이는 알파벳에는 유용하지만 한국어에는 적용하기 어렵습니다.
POST movie_search/_search
{
"query": {
"match": {
"movieNmEn": {
"query": "Fli High", # "Fly High" 검색 가능
"fuzziness": 1
}
}
}
}
9) boost
관련성이 높은 필드나 키워드에 가중치를 더 줄 수 있게 해줍니다. 아래 예는 한글 영화 제목이 일치하면 한글 영화 제목에서 계산되는 스코어에 가중치 값으로 3을 곱합니다.
POST movie_search/_search
{
"query" : {
"multi_match": {
"query": "Fly",
"fields": ["movieNm^3","movieNmEn"]
}
}
}