Elasticsearch Query DSL¶
복잡한 검색 조건을 만드려면 "이 단어를 포함하고, 날짜가 이 범위면서, 이 상태인 문서" 같은 요구를 표현할 방법이 필요해요. Elasticsearch는 이를 위한 Query DSL 이라는 JSON 스타일 쿼리 언어를 제공합니다. 전문검색부터 필터링, 집계까지 하나로 다루는 Elasticsearch의 원래·가장 강력한 쿼리 언어예요. 이 페이지는 소스 문서 Elasticsearch Query DSL 를 바탕으로 설명해요.
개요¶
Query DSL은 _search 엔드포인트가 받는 쿼리를 쓰는 언어입니다. 쿼리는 리프(leaf) 쿼리와 복합(compound) 쿼리 두 종류의 절(clause)로 구성돼요. 리프 쿼리는 특정 필드에서 특정 값을 찾고(match, term, range), 복합 쿼리는 여러 쿼리를 bool이나 dis_max처럼 논리적으로 묶거나 constant_score처럼 동작을 바꿉니다. 이 절들이 쿼리 컨텍스트에서 쓰이느냐 필터 컨텍스트에서 쓰이느냐에 따라 동작이 달라져요.
핵심 개념¶
쿼리 컨텍스트(Query Context)와 필터 컨텍스트(Filter Context)¶
쿼리 절이 어디에 들어가는지에 따라 두 가지로 나뉩니다.
- 쿼리 컨텍스트 — "이 문서가 이 쿼리에 얼마나 잘 맞나?"를 묻고, 매칭 여부와 함께 관련도 점수(
_score) 를 계산합니다.query파라미터에 넘어가는 절이 여기 해당해요. - 필터 컨텍스트 — "이 문서가 조건에 맞나?"를 예/아니오로만 답하고, 점수를 계산하지 않습니다.
bool의filter·must_not,constant_score의filter가 여기예요.
필터는 점수를 안 내서 쿼리보다 빠르고, 자주 쓰이는 필터는 Elasticsearch가 자동으로 캐시하기 때문에 재사용 시 더 빨라져요. 그래서 정확한 "반드시" 조건(구조화 데이터)은 필터로 거는 게 효율적입니다.
GET /_search
{
"query": {
"bool": {
"must": [
{ "match": { "title": "Search" }},
{ "match": { "content": "Elasticsearch" }}
],
"filter": [
{ "term": { "status": "published" }},
{ "range": { "publish_date": { "gte": "2015-01-01" }}}
]
}
}
}
must의 match는 관련도 점수에 기여하고, filter의 term·range는 매칭 여부만 결정해 결과를 걸러냅니다.
관련도 점수¶
기본적으로 검색 결과는 관련도 점수(_score) 로 정렬돼요. 점수는 양수 실수로, 높을수록 관련이 크다는 뜻입니다. 점수 계산 방식은 쿼리마다 다르고, 쿼리 컨텍스트인지 필터 컨텍스트인지에도 영향을 받아요.
값비싼 쿼리 제한¶
일부 쿼리(script, fuzzy, regexp, wildcard, range-on-text 등)는 구현 방식 때문에 본질적으로 느려 클러스터 안정성에 영향을 줄 수 있어요. search.allow_expensive_queries 설정(기본 true)을 false로 두면 이런 쿼리 실행을 막을 수 있습니다.
집계(Aggregations)¶
Query DSL로 검색·필터뿐 아니라 집계로 분석도 할 수 있어요. 집계는 검색과 같은 데이터 구조를 쓰기 때문에 빠르고, 같은 요청에서 문서 검색·필터·분석을 한 번에 할 수 있어요. 메트릭(합·평균), 버킷(값·범위로 그룹핑), 파이프라인(집계 결과에 집계)이 주요 유형입니다.
실제 적용 (데이터스케쳐스)¶
- 하이브리드 검색 —
match(키워드)와 kNN(벡터) 결과를 RRF로 합쳐 순위를 만듭니다. - 메타데이터 필터링 —
bool필터로 문서 종류·날짜·테넌트를 걸러 후보를 좁힙니다. - 정확한 용어 매칭 —
term쿼리로 코드·약어·고유명사를 정확히 찾습니다. - 비용·지연 관리 — 값비싼 쿼리 제한 설정으로 클러스터 안정성을 지킵니다.
더 알아보기¶
- 공식 문서 (1차): Elasticsearch Query DSL, bool 쿼리, match 쿼리
- 큐레이션/블로그 (2차): Elastic 블로그