Elasticsearch는 강력한 검색 엔진으로, 복잡한 검색 조건을 표현하기 위한 Query DSL(Domain Specific Language)을 제공합니다. 이 글에서는 Elasticsearch 검색에서 자주 사용되는 주요 키워드와 쿼리 타입에 대해 알아보겠습니다.
Bool 복합쿼리 구조
Bool 쿼리는 여러 쿼리 조건을 결합하여 복잡한 검색 로직을 구현할 수 있게 해주는 복합 쿼리입니다. 기본 구조는 다음과 같습니다.
GET <인덱스명>/_search
{
"query": {
"bool": {
"must": [
{ <쿼리> }, …
],
"must_not": [
{ <쿼리> }, …
],
"should": [
{ <쿼리> }, …
],
"filter": [
{ <쿼리> }, …
]
}
}
}
Bool 쿼리에는 네 가지 주요 절이 있습니다:
1. must 절
must 절은 문서가 반드시 충족해야 하는 조건을 지정합니다. 이는 SQL의 AND 연산자와 유사하게 작동합니다. must 절 내의 모든 조건을 만족하는 문서만 검색 결과에 포함됩니다. 검색 점수(relevance score)에 영향을 주며, 조건이 정확히 일치할수록 높은 점수를 받게 됩니다.
2. filter 절
filter 절은 must와 유사하게 문서가 충족해야 하는 조건을 지정하지만, 중요한 차이점이 있습니다:
- 검색 점수에 영향을 주지 않습니다(Yes/No 바이너리 결정만 수행)
- 자주 사용되는 필터 결과는 메모리에 캐싱되어 성능이 향상됩니다
- 점수 계산이 없어 must보다 더 효율적으로 작동합니다
실무에서는 정확한 일치가 필요하지만 관련성 점수가 중요하지 않은 경우(예: 날짜 범위, 카테고리 필터링) filter를 사용하는 것이 좋습니다.
3. should 절
should 절은 선택적 조건을 나타내며, SQL의 OR 연산자와 유사합니다. 문서가 should 조건을 충족할 경우 검색 점수가 높아지지만, 필수는 아닙니다. 다만, must 절이 없고 should 절만 있는 경우에는 최소 하나 이상의 should 조건을 충족해야 합니다.
4. must_not 절
must_not 절은 부정 조건을 나타냅니다. 이 절에 지정된 조건을 충족하는 문서는 검색 결과에서 제외됩니다. must_not은 filter와 마찬가지로 검색 점수에 영향을 주지 않습니다.
주요 쿼리 타입
1. range 쿼리
숫자나 날짜 필드에 대한 범위 검색을 수행할 때 사용합니다.
GET /products/_search
{
"query": {
"range": {
"price": {
"gte": 100,
"lte": 200
}
}
}
}
주요 파라미터:
- gt: 초과(>)
- gte: 이상(>=)
- lt: 미만(<)
- lte: 이하(<=)
2. exists 쿼리
특정 필드가 존재하는 문서만 검색할 때 사용합니다. MongoDB의 $exists 연산자와 유사합니다.
GET /products/_search
{
"query": {
"exists": {
"field": "tags"
}
}
}
3. prefix 쿼리
특정 접두어로 시작하는 값을 가진 문서를 검색할 때 사용합니다.
GET /products/_search
{
"query": {
"prefix": {
"sku": "ABC"
}
}
}
4. wildcard 쿼리
와일드카드 패턴을 사용한 문자열 검색을 수행합니다.
GET /company/_search
{
"from": 0,
"size": 50,
"query": {
"wildcard": {
"companyName": "삼성*"
}
}
}
*는 0개 이상의 문자를,? 는 정확히 1개의 문자를 나타냅니다.
5. regexp 쿼리
정규표현식 패턴을 사용한 검색을 수행합니다.
GET /products/_search
{
"query": {
"regexp": {
"sku": "A[0-9].+"
}
}
}
6. match 쿼리
전문 검색에 가장 많이 사용되는 쿼리 타입입니다. 기본적으로 검색어를 분석하여 토큰으로 나누고, 각 토큰이 OR 조건으로 결합됩니다:
GET company/_search
{
"query": {
"match": {
"info": {
"query": "삼성 음악",
"operator": "and"
}
}
}
}
operator를 and로 설정하면 모든 토큰이 문서에 존재해야 합니다.
7. match_phrase 쿼리
검색어 토큰들이 정확한 순서로 인접하게 나타나는 문서를 검색합니다.
GET company/_search
{
"query": {
"match_phrase": {
"message": {
"query": "2차 산업",
"slop": 1
}
}
}
}
slop 파라미터는 토큰 사이에 허용되는 추가 단어 수를 지정합니다. 위 예제에서 slop: 1로 설정하면 "2차 전지 산업"과 같이 두 단어 사이에 다른 단어가 하나 있는 문서도 검색 결과에 포함됩니다.
8. query_string 쿼리
Lucene 쿼리 구문을 직접 사용할 수 있는 강력한 쿼리입니다.
GET company/_search
{
"query": {
"query_string": {
"default_field": "info",
"query": "(2차 AND 전지) OR \"방위 산업\""
}
}
}
AND, OR, NOT 연산자, 괄호를 사용한 그룹화, 와일드카드, 정규식 등 다양한 검색 표현을 지원합니다.
실무 활용 팁
- 성능 최적화: 점수 계산이 필요하지 않은 필터링에는 filter 절을 사용하세요.
- 복합 검색 조건: 다양한 비즈니스 요구사항에 맞게 bool 쿼리의 여러 절을 조합하세요.
- 전문 검색: 자연어 검색에는 match 또는 match_phrase를 사용하세요.
- 정확한 필터링: 숫자, 날짜, 카테고리 등의 정확한 필터링에는 term, range, exists 쿼리를 활용하세요.
Elasticsearch Query DSL은 매우 유연하고 강력하므로, 이러한 기본 요소들을 잘 조합하면 복잡한 검색 요구사항도 효과적으로 구현할 수 있습니다.