Elasticsearch: 날짜(Date) 타입 완벽 정리

Elasticsearch에서 날짜(Date) 타입ISO8601 형식을 따르며, 다양한 날짜 포맷을 지원합니다.
ISO8601 기본 형식: "2019-06-12T17:13:40.428Z"
epoch_millis: 1970-01-01 00:00:00부터 경과한 밀리초
사용자 정의 포맷 설정 가능

이번 글에서는 날짜 타입의 기본 개념, 주요 옵션, 포맷 지정 방법, 그리고 Range Query 활용법까지 상세히 알아보겠습니다.


1. Elasticsearch에서 날짜(Date) 타입의 기본 개념

🔹 기본 날짜 형식 (ISO8601)

Elasticsearch는 ISO8601 형식을 기본적으로 지원합니다.

📌 자동으로 날짜로 인식되는 형식 예제

"2019-06-12"
"2019-06-12T17:13:40"
"2019-06-12T17:13:40+09:00"
"2019-06-12T17:13:40.428Z"

위 형식으로 입력하면 자동으로 날짜 타입으로 저장됨

📌 자동으로 문자열(text)로 저장되는 잘못된 날짜 형식 예제

"2019/06/12 12:10:30"  // "/" 사용 (기본 설정에서는 text로 저장됨)

이 경우 format 옵션을 설정해야 날짜로 저장 가능!


2. 날짜(Date) 타입 필드 설정

🔹 기본 날짜 타입 매핑 예제

PUT my_date
{
  "mappings": {
    "properties": {
      "date_val": {
        "type": "date"
      }
    }
  }
}

기본적으로 ISO8601 형식을 사용하며, long 타입의 epoch_millis도 저장 가능


3. 날짜(Date) 타입의 주요 옵션

Elasticsearch의 날짜 타입 필드는 문자열, 숫자 필드와 일부 동일한 옵션을 가집니다.

옵션 설명 기본값

옵션 설명 기본값
index 색인 여부 (검색 가능 여부) true
doc_values 집계/정렬을 위한 최적화된 저장 방식 사용 여부 true
null_value null 값이 입력될 경우 기본값 설정 없음
ignore_malformed 잘못된 날짜 입력 시 오류를 무시하고 저장할지 여부 false
format 날짜 입력 형식 지정 (여러 개 가능) `strict_date_optional_tim

4. 날짜 포맷 설정하기

기본적으로 Elasticsearch는 ISO8601 형식만 지원하지만,
format 옵션을 사용하여 다양한 날짜 형식을 추가할 수 있음

📌 예제 1: 다양한 날짜 형식 지원 (yyyy/MM/dd, yyyy-MM-dd HH:mm:ss, epoch_millis)

PUT my_date
{
  "mappings": {
    "properties": {
      "date_val": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
      }
    }
  }
}

지원되는 날짜 형식 예제

  • "2019-06-10 12:10:30"
  • "2019/06/10"
  • 1560127830000 (epoch_millis)

5. Elasticsearch에서 지원하는 날짜 포맷

다양한 날짜 포맷을 사용할 수 있으며, 아래와 같은 Joda-Time 심볼을 활용하여 설정할 수 있습니다.

📌 주요 날짜 포맷 심볼

심볼 의미 예제 (2019-09-12T17:13:07.428+09:00)
yyyy 년도 2019
MM 월(숫자) 09
MMM 월(문자, 3자리) Sep
MMMM 월(문자, 전체) September
dd 일(숫자) 12
a 오전/오후 PM
HH 24시간제 시간 (00~23) 17
hh 12시간제 시간 (01~12) 05
mm 분 (00~59) 13
ss 초 (00~59) 07
SSS 밀리초 428
Z 타임존 +09:00

6. 날짜 데이터 저장 및 검색 예제

📌 예제 2: 날짜 데이터 저장 (ISO8601)

PUT my_date/_doc/1
{
  "date_val": "2019-09-12 15:01:23"
}

✅ "2019-09-12 15:01:23"이 저장됨

📌 예제 3: Range Query (날짜 범위 검색)

GET my_date/_search
{
  "query": {
    "range": {
      "date_val": {
        "gt": "2019/09/10",
        "lt": 1568332800000
      }
    }
  }
}

다른 날짜 포맷을 사용해도 정상적으로 검색됨!

📌 예제 4: 현재 시간(now) 기준 검색

GET my_date/_search
{
  "query": {
    "range": {
      "date_val": {
        "gte": "now-1M",
        "lt": "now"
      }
    }
  }
}

최근 1개월 동안의 데이터 검색 가능


7. 날짜 데이터의 내부 저장 방식

모든 날짜 값은 내부적으로 epoch_millis (1970-01-01 00:00:00 UTC 기준 밀리초)로 변환하여 저장됨
✔ 하지만 검색 시에는 다양한 날짜 형식으로 조회 가능

📌 예제 5: _source 데이터 확인

GET my_date/_doc/1

🔹 결과 예제

{
  "_source": {
    "date_val": "2019-09-12 15:01:23"
  }
}

날짜 입력 값은 그대로 유지되지만, 내부적으로는 epoch_millis로 변환되어 저장됨


8. 정리

개념 설명
ISO8601 형식 기본 날짜 형식 (2019-06-12T17:13:40.428Z)
epoch_millis 1970-01-01 00:00:00 UTC부터의 밀리초 값
format 옵션 다양한 날짜 형식 지정 가능 (yyyy/MM/dd, epoch_millis 등)
현재 시간(now) 활용 now-1d, now-1M 같은 상대적 날짜 검색 가능
내부 저장 방식 모든 날짜는 epoch_millis로 변환 후 저장됨

9. 학습 가이드

1️⃣ ISO8601 형식 및 epoch_millis를 사용하여 데이터 저장 실습
2️⃣ format 옵션을 활용하여 다양한 날짜 형식 적용
3️⃣ Range Query를 사용하여 날짜 범위 검색 실습
4️⃣ 현재 시간(now) 기반 상대적 날짜 검색 테스트


10. 마무리

Elasticsearch의 날짜(Date) 타입다양한 포맷을 지원하며, epoch_millis로 변환하여 저장됩니다.
특히 format 옵션, range 쿼리, now 키워드를 활용하면 날짜 데이터를 효과적으로 관리할 수 있습니다.

다음 학습에서는 Range Query를 활용한 고급 날짜 검색 최적화 방법을 다루겠습니다! 🚀

Elasticsearch: 숫자 데이터 타입 (long, double, scaled_float 등) 완벽 정리

Elasticsearch는 **정수(Integer)와 실수(Float)**를 저장할 수 있도록 다양한 숫자 타입을 제공합니다.
정수 타입: long, integer, short, byte
실수 타입: double, float, half_float, scaled_float

이번 글에서는 각 숫자 타입의 특징, 주요 옵션, 그리고 실전 적용 예제까지 상세히 알아보겠습니다.


1. Elasticsearch에서 숫자 타입

🔹 기본 숫자 타입

Elasticsearch는 자바(Java)에서 사용되는 기본 숫자 타입을 지원합니다.

타입 설명 범위
long 64비트 정수 -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
integer 32비트 정수 -2,147,483,648 ~ 2,147,483,647
short 16비트 정수 -32,768 ~ 32,767
byte 8비트 정수 -128 ~ 127
double 64비트 부동소수점 매우 큰 실수값 저장 가능
float 32비트 부동소수점 일반적인 실수 저장
half_float 16비트 부동소수점 작은 크기의 실수 저장
scaled_float 부동소수점을 정수(long)로 저장하며, 소수점 위치 지정 가능 scaling_factor 사용

2. 숫자 필드의 주요 옵션

Elasticsearch의 숫자 필드는 text, keyword와 일부 동일한 옵션을 가집니다.

옵션 설명 기본값
index 색인 여부 (검색 가능 여부) true
doc_values 집계/정렬을 위한 최적화된 저장 방식 사용 여부 true
boost 검색 시 가중치 부여 1
coerce 자동 형 변환 허용 여부 true
null_value null 값이 입력될 경우 기본값 설정 없음
ignore_malformed 잘못된 숫자 입력 시 오류를 무시하고 저장할지 여부 false

3. 정수(Integer) 타입 예제

📌 예제 1: 정수 타입 매핑 설정

PUT my_index
{
  "mappings": {
    "properties": {
      "price": {
        "type": "integer",
        "coerce": true
      }
    }
  }
}

🔹 설명:

  • "coerce": true → 4.5, "5" 등의 값도 4 또는 5로 자동 변환되어 저장됨 ✅

4. 실수(Floating Point) 타입 예제

📌 예제 2: 실수 타입 매핑 설정

PUT my_index
{
  "mappings": {
    "properties": {
      "rating": {
        "type": "float",
        "coerce": true
      }
    }
  }
}

🔹 설명:

  • "rating": 4.7 → 그대로 저장됨 ✅

5. Scaled Float (소수점 고정형 실수)

🔹 Scaled Float이란?

부동소수점을 정수(long)로 변환하여 저장
소수점 위치를 scaling_factor로 조정
금액($19.99)과 같은 고정 소수점 데이터에 유용

📌 예제 3: scaled_float 타입 매핑 설정

PUT my_index
{
  "mappings": {
    "properties": {
      "price": {
        "type": "scaled_float",
        "scaling_factor": 100
      }
    }
  }
}

🔹 설명:

  • "price": 19.99 → 1999로 변환 후 저장됨
  • "price": 100.25 → 10025로 저장됨

📌 주의:
scaling_factor: 100 이므로 두 자리 소수점까지 저장 가능

  • scaling_factor: 10 → 1자리 소수점까지만 저장 가능

6. 숫자 필드의 중요한 옵션 실전 예제

📌 예제 4: 숫자 필드에서 coerce, null_value, ignore_malformed 활용

PUT my_index
{
  "mappings": {
    "properties": {
      "quantity": {
        "type": "integer",
        "coerce": true,
        "null_value": 0,
        "ignore_malformed": true
      }
    }
  }
}

🔹 설명:

  • "coerce": true → "4.5", "6" 등의 값도 정수로 변환 ✅
  • "null_value": 0 → null 값이 입력되면 0으로 저장 ✅
  • "ignore_malformed": true → 숫자가 아닌 값이 입력되면 오류 없이 저장하되, 검색 및 집계에서 무시 ✅

7. 숫자 필드의 동적 매핑 문제점

숫자 필드를 동적으로 생성하면 위험할 수 있음
첫 번째 값이 4 같은 정수라면 long으로 자동 생성
✔ 이후에 5.5 같은 실수가 들어오면 자동 변환되지만 실제로는 5가 저장됨

📌 잘못된 동적 매핑 예제

PUT my_index/_doc/1
{
  "value": 4
}
PUT my_index/_doc/2
{
  "value": 5.5
}

🔹 문제:

  • value 필드가 long으로 자동 생성
  • 5.5가 입력되었지만 5로 저장됨 (소수점 손실 발생) ❗

해결 방법: 명시적 매핑 설정 사용!

PUT my_index
{
  "mappings": {
    "properties": {
      "value": {
        "type": "float"
      }
    }
  }
}

📌 이제 5.5가 올바르게 저장됨!


8. 정리

개념 설명
long, integer, short, byte 정수 타입 (64비트, 32비트, 16비트, 8비트)
double, float, half_float 부동소수점 실수 (정확도 차이)
scaled_float 부동소수점을 long 형태로 변환하여 저장 (scaling_factor 필요)
coerce 문자열 숫자를 자동 변환 ("4.5" → 4)
null_value null 값이 입력될 경우 기본값 설정
ignore_malformed 잘못된 숫자 입력 시 오류 없이 무시

9. 학습 가이드

1️⃣ 각 숫자 타입을 사용하여 데이터를 저장하고 검색하는 실습 진행
2️⃣ coerce, null_value, ignore_malformed 옵션을 활성화하고 동작 방식 실험
3️⃣ scaled_float을 활용하여 금액 데이터를 저장하고 검색 테스트
4️⃣ 동적 매핑으로 인한 문제를 직접 경험하고 해결 방법 적용


10. 마무리

Elasticsearch에서 숫자 타입을 올바르게 설정하는 것은 데이터의 정확성과 검색 성능을 높이는 중요한 요소입니다.
특히 정수 vs 실수, scaled_float 활용, 동적 매핑의 위험성을 이해하고 적절한 설정을 적용하는 것이 중요합니다.

다음 학습에서는 날짜(Date) 타입을 활용한 검색 및 최적화 방법을 다루겠습니다! 🚀

Elasticsearch: 문자열 타입 (text vs keyword) 완벽 이해

Elasticsearch에서는 문자열 데이터를 저장할 때 text 타입keyword 타입을 사용할 수 있습니다.
text: 검색을 위해 분석(Analyzed)되어 저장됨 (풀 텍스트 검색용)
keyword: 분석 없이 원본 그대로 저장됨 (정확한 값 검색 및 정렬, 집계용)

이 글에서는 text와 keyword의 차이, 각각의 주요 옵션, 그리고 실전 적용 예제까지 상세히 알아보겠습니다.


1. Elasticsearch에서 문자열 데이터 저장 방식

🔹 문자열 데이터 저장 방식의 변화

Elasticsearch 2.x 이전에는 문자열(string) 타입만 존재했으며, 분석 여부를 옵션으로 구분했습니다.
하지만 5.0 이후부터는 textkeyword 타입으로 나뉘면서, 텍스트 분석 여부를 명확히 구분하게 되었습니다.


2. text 타입 (검색용)

🔹 text란?

  • 텍스트 분석기(Analyzer)를 적용하여 검색 최적화
  • 문자열을 여러 개의 토큰(Token)으로 분리하여 역색인(Inverted Index) 저장
  • 대용량 텍스트(본문, 설명, 제목 등)에 적합
  • 집계(Aggregation)와 정렬(Sorting)에 비효율적 (메모리 사용량 증가)

📌 예제 1: text 필드 매핑

PUT my_index
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      }
    }
  }
}

🔹 "The quick brown fox" → ["the", "quick", "brown", "fox"] 로 저장됨 ✅

🔹 text 필드의 주요 옵션

옵션 설명 기본값
analyzer 색인 시 사용할 애널라이저 설정 standard
search_analyzer 검색 시 사용할 애널라이저 설정 색인 애널라이저와 동일
index 색인 여부 (검색 가능 여부) true
boost 검색 시 가중치 부여 1
fielddata 집계/정렬 가능 여부 (true 시 메모리 사용 증가) false

📌 예제 2: custom analyzer 적용

PUT my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "custom_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [ "lowercase", "stop" ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "description": {
        "type": "text",
        "analyzer": "custom_analyzer"
      }
    }
  }
}

🔹 설명:

  • "The QUICK brown fox" → ["quick", "brown", "fox"] 로 저장됨 (대소문자 변환, 불용어 제거)

3. keyword 타입 (정확한 값 검색 및 정렬)

🔹 keyword란?

  • 분석되지 않고 원본 그대로 저장
  • 정확한 값 비교(Exact Matching), 필터링, 정렬, 집계에 최적화
  • 소문자 변환, 불용어 제거 등의 처리가 필요 없다면 사용
  • 검색에는 부적합하지만, 집계(Aggregation)에는 필수

📌 예제 3: keyword 필드 매핑

PUT my_index
{
  "mappings": {
    "properties": {
      "category": {
        "type": "keyword"
      }
    }
  }
}

🔹 "The quick brown fox" → ["The quick brown fox"] 그대로 저장 ✅


🔹 keyword 필드의 주요 옵션

옵션 설명 기본값
doc_values 집계/정렬 시 메모리 사용 최적화 true
ignore_above 특정 길이 이상 문자열 색인 제외 256 (동적 매핑 시)
normalizer 대소문자 변환 등 기본적인 문자 변환 가능 없음

📌 예제 4: normalizer 적용 (소문자 변환)

PUT my_index
{
  "settings": {
    "analysis": {
      "normalizer": {
        "custom_normalizer": {
          "type": "custom",
          "filter": ["lowercase"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "tag": {
        "type": "keyword",
        "normalizer": "custom_normalizer"
      }
    }
  }
}

🔹 "Elasticsearch" → "elasticsearch" 로 변환 후 저장


4. text vs keyword 비교

비교 항목 text keyword
저장 방식 분석(Analyzed) 후 토큰화됨 원본 그대로 저장
검색 방식 풀 텍스트 검색 (Match Query) 정확한 값 검색 (Term Query)
정렬(Sorting) ❌ 불가능 (fielddata 필요) ✅ 가능
집계(Aggregation) ❌ 비효율적 ✅ 최적
필터(Filter) ❌ 비효율적 ✅ 최적
애널라이저 사용 ✅ 가능 ❌ 불가능 (normalizer 사용 가능)

📌 keyword 필드의 Term Query 예제

GET my_index/_search
{
  "query": {
    "term": {
      "category": "Elasticsearch"
    }
  }
}

"Elasticsearch"와 정확히 일치하는 문서만 검색

📌 text 필드의 Match Query 예제

GET my_index/_search
{
  "query": {
    "match": {
      "title": "Elasticsearch Guide"
    }
  }
}

"Elasticsearch"와 "Guide"가 포함된 문서 검색


5. text와 keyword 함께 사용하기 (Multi-Field)

Elasticsearch에서는 text와 keyword를 동시에 사용할 수 있습니다.
✔ 검색 시 text 필드 사용
✔ 필터링, 정렬, 집계 시 keyword 필드 사용

📌 예제 5: Multi-Field 설정

PUT my_index
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}

🔹 검색: title 필드 사용
🔹 정렬/집계: title.keyword 필드 사용

📌 Match Query (검색)

GET my_index/_search
{
  "query": {
    "match": {
      "title": "Elasticsearch Guide"
    }
  }
}

"Elasticsearch Guide" 관련 문서 검색

📌 Term Query (정확한 값 검색)

GET my_index/_search
{
  "query": {
    "term": {
      "title.keyword": "Elasticsearch Guide"
    }
  }
}

"Elasticsearch Guide"와 정확히 일치하는 문서 검색


6. 정리

개념 설명
text 타입 분석(Analyzed)되어 검색 최적화, 집계/정렬 비효율적
keyword 타입 원본 그대로 저장, 필터링/정렬/집계 최적화
text 필드 옵션 analyzer, search_analyzer, boost, fielddata
keyword 필드 옵션 doc_values, ignore_above, normalizer
Multi-Field 사용 검색(text) + 집계/정렬(keyword) 함께 사용

7. 학습 가이드

1️⃣ text와 keyword 차이를 실습하며 비교
2️⃣ Analyzer와 Normalizer를 적용하여 다양한 문자열 처리 연습
3️⃣ Multi-Field 설정하여 검색 및 정렬 최적화
4️⃣ keyword 필드를 활용한 Term Query & Aggregation 실습

다음 학습에서는 Analyzer와 Tokenizer를 활용한 텍스트 분석 심화 과정을 다루겠습니다! 🚀

Elasticsearch: 매핑(Mappings) 이해하기

Elasticsearch에서 **매핑(Mappings)**은 인덱스 내 문서의 필드 유형 및 분석 방법을 정의하는 중요한 요소입니다.
동적 매핑(Dynamic Mapping): 자동으로 필드 타입을 생성
명시적 매핑(Explicit Mapping): 직접 필드 타입을 정의

이번 글에서는 매핑의 개념, 동적 매핑과 명시적 매핑의 차이, 그리고 필드 타입 설정 방법을 상세히 알아보겠습니다.


1. Elasticsearch의 매핑(Mappings) 개념

🔹 매핑이란?

  • Elasticsearch에서 문서의 각 필드에 대한 데이터 타입을 정의하는 과정입니다.
  • 인덱스를 생성할 때 매핑을 설정하면 필드의 타입을 명확히 지정하여 데이터의 일관성을 유지할 수 있습니다.
  • 매핑 정보는 GET <인덱스명>/_mapping 명령어로 확인할 수 있습니다.

📌 매핑 조회 예제

GET books/_mapping

🔹 결과 예제 (자동 매핑 적용 후)

{
  "books": {
    "mappings": {
      "properties": {
        "title": {
          "type": "text"
        },
        "author": {
          "type": "text"
        },
        "category": {
          "type": "keyword"
        },
        "publish_date": {
          "type": "date"
        },
        "pages": {
          "type": "long"
        }
      }
    }
  }
}

📌 설명:

  • title, author → text (검색 가능)
  • category → keyword (정확한 값 비교)
  • publish_date → date (ISO 8601 형식)
  • pages → long (정수)

2. 동적(Dynamic) 매핑

🔹 동적 매핑이란?

Elasticsearch는 새로운 필드가 문서에 추가될 경우 자동으로 매핑을 생성하는 기능을 제공합니다.
즉, 사전에 필드를 정의하지 않아도 문서를 색인하면 자동으로 매핑이 설정됩니다.

📌 예제 1: books 인덱스 없이 문서 입력

PUT books/_doc/1
{
  "title": "Romeo and Juliet",
  "author": "William Shakespeare",
  "category": "Tragedies",
  "publish_date": "1562-12-01T00:00:00",
  "pages": 125
}

📌 자동 매핑 결과 확인

GET books/_mapping

🔹 자동 매핑 결과

  • title, author: text
  • category: keyword
  • publish_date: date
  • pages: long

3. 명시적(Explicit) 매핑

🔹 명시적 매핑이란?

  • 데이터가 인덱싱되기 전에 필드 타입을 미리 정의하는 방식입니다.
  • 자동 매핑은 필드 타입이 의도와 다르게 설정될 수 있으므로, 중요한 필드는 명시적으로 설정하는 것이 좋습니다.
  • 특히 숫자, 날짜, 키워드 필드는 명확한 설정이 필요합니다.

📌 예제 2: 명시적 매핑 설정

PUT books
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "author": {
        "type": "text"
      },
      "category": {
        "type": "keyword"
      },
      "publish_date": {
        "type": "date"
      },
      "pages": {
        "type": "integer"
      }
    }
  }
}

🔹 설명

  • title, author: text (검색 최적화)
  • category: keyword (필터링 및 정렬 가능)
  • publish_date: date (날짜 필드)
  • pages: integer (정수값)

📌 새로운 문서 입력 (매핑 유지됨)

PUT books/_doc/2
{
  "title": "Hamlet",
  "author": "William Shakespeare",
  "category": "Tragedies",
  "publish_date": "1603-01-01T00:00:00",
  "pages": 200
}

📌 매핑 확인

GET books/_mapping

🔹 결과: 기존 설정된 필드 타입이 유지됨 ✅


4. 기존 인덱스에 필드 추가

Elasticsearch에서는 기존 인덱스에 새로운 필드를 추가할 수 있지만, 기존 필드의 타입 변경은 불가능합니다.

📌 예제 3: 기존 인덱스에 publisher 필드 추가

PUT books/_mapping
{
  "properties": {
    "publisher": {
      "type": "keyword"
    }
  }
}

📌 매핑 확인

GET books/_mapping

🔹 결과: publisher 필드가 keyword 타입으로 추가됨 ✅

하지만 기존 필드의 타입 변경은 불가능

PUT books/_mapping
{
  "properties": {
    "pages": {
      "type": "float"  ❌ (에러 발생)
    }
  }
}

이미 설정된 필드 타입은 변경 불가능 → 새로운 인덱스를 만들어 데이터를 재색인해야 함


5. 주요 데이터 타입 정리

Elasticsearch에서 사용할 수 있는 주요 데이터 타입을 정리하면 다음과 같습니다.

데이터 타입 설명
text 전문 검색(Full-Text Search)용 필드
keyword 정확한 값 비교, 필터링, 정렬
integer 정수값
long 큰 정수값
float 소수점 포함 숫자
double 높은 정밀도의 소수점 숫자
date 날짜 필드 (ISO 8601)
boolean true/false 값
object JSON 객체 저장
nested 다중 필드(Nested Documents)

6. 정리

개념 설명
동적 매핑 (Dynamic Mapping) 문서가 입력될 때 자동으로 필드 타입을 생성
명시적 매핑 (Explicit Mapping) 필드 타입을 사전에 정의하여 데이터의 일관성 유지
기존 인덱스에 필드 추가 가능 여부 ✅ 새로운 필드는 추가 가능
기존 필드 타입 변경 가능 여부 ❌ 기존 필드 타입 변경 불가능 (재색인 필요)

7. 학습 가이드

1️⃣ 동적 매핑과 명시적 매핑을 비교하며 실습
2️⃣ 다양한 필드 타입을 정의하고 검색 결과 비교
3️⃣ keyword와 text 필드의 차이를 이해하고 적절히 사용
4️⃣ 기존 필드 타입 변경이 불가능하므로, 새로운 인덱스를 생성하고 데이터 재색인 연습


8. 마무리

Elasticsearch에서 **매핑(Mappings)**은 데이터를 효율적으로 저장하고 검색하는 데 중요한 역할을 합니다.
특히 keyword vs text, 동적 매핑 vs 명시적 매핑, 기존 필드 타입 변경 불가능 등의 개념을 이해하고 올바르게 활용하는 것이 중요합니다.

다음 학습에서는 Nested & Object 타입을 활용한 문서 구조 설계 방법을 다루겠습니다! 🚀

Elasticsearch: 설정(Settings) 이해하기

Elasticsearch에서 **인덱스를 생성할 때 필요한 설정(Settings)**은 매우 중요한 요소입니다.
모든 인덱스는 두 개의 핵심 정보 단위를 가지며,
Settings (설정): 인덱스의 기본적인 동작을 정의
Mappings (매핑): 필드의 데이터 유형과 분석 방법을 지정

이번 글에서는 Settings의 개념, 주요 설정 요소, 그리고 변경 가능 여부에 대해 상세히 알아보겠습니다.


1. Elasticsearch Settings란?

🔹 기본 개념

  • Settings는 Elasticsearch 인덱스의 구성 및 동작을 정의하는 설정 값입니다.
  • 주요 설정에는 샤드(Shard) 개수, 복제본(Replica) 개수, 리프레시 간격(refresh_interval), 애널라이저(analyzer) 등이 포함됩니다.
  • 인덱스를 생성할 때 설정되며, 일부 설정은 운영 중에도 변경 가능하지만, 일부는 한 번 설정되면 변경 불가능합니다.

📌 인덱스 정보 조회 예제

GET my_index

🔹 결과:

  • settings → 인덱스의 설정 정보
  • mappings → 필드 타입 및 매핑 정보

📌 설정만 따로 조회

GET my_index/_settings

📌 매핑 정보만 따로 조회

GET my_index/_mappings

2. 샤드(Shard)와 복제본(Replica) 설정

🔹 샤드(Shard)란?

  • Elasticsearch의 인덱스는 여러 개의 샤드(Shard)로 분할 저장됩니다.
  • 기본적으로 하나의 인덱스는 **프라이머리 샤드(Primary Shard)와 복제 샤드(Replica Shard)**로 구성됩니다.

설정 값 설명 기본값

number_of_shards 인덱스의 프라이머리 샤드 개수 7.x부터 기본값 1
number_of_replicas 복제본 개수 (프라이머리 샤드 당) 7.x부터 기본값 1

📌 샤드 & 복제본 설정 예제

PUT my_index
{
  "settings": {
    "index": {
      "number_of_shards": 3,
      "number_of_replicas": 1
    }
  }
}

🔹 샤드 개수 변경 가능 여부

  • number_of_replicas운영 중 변경 가능
  • number_of_shards인덱스 생성 후 변경 불가

📌 복제본 개수 변경 예제

PUT my_index/_settings
{
  "number_of_replicas": 2
}

📌 샤드 개수 변경이 필요한 경우
샤드 개수를 변경하려면 새로운 인덱스를 생성하고 기존 데이터를 다시 색인(reindexing) 해야 합니다.


3. Refresh Interval 설정

🔹 Refresh Interval이란?

  • Elasticsearch는 새로운 문서를 색인한 후 일정 주기로 검색 가능하도록 처리합니다.
  • 이 주기를 refresh interval이라고 하며, 기본값은 1초(1s) 입니다.
  • 값을 늘리면 색인 성능이 향상되지만, 검색 반영이 느려질 수 있음

📌 refresh_interval 설정 예제 (30초로 변경)

PUT my_index
{
  "settings": {
    "refresh_interval": "30s"
  }
}

📌 운영 중 refresh_interval 변경 가능

PUT my_index/_settings
{
  "refresh_interval": "5s"
}

색인 작업이 많을 때는 "refresh_interval": "-1" 로 설정하여 자동 리프레시를 비활성화하고, 배치 색인 후 POST my_index/_refresh 를 실행하여 직접 리프레시할 수도 있습니다.


4. Analyzer, Tokenizer, Filter 설정

Elasticsearch에서 **애널라이저(Analyzer)**를 설정하려면 settings 내부의 analysis 항목을 사용합니다.

📌 사용자 정의 애널라이저 설정 예제

PUT my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "type": "custom",
          "char_filter": [ "html_strip" ],
          "tokenizer": "standard",
          "filter": [ "lowercase", "stop" ]
        }
      }
    }
  }
}

🔹 설명

  • "type": "custom" → 사용자 정의 애널라이저
  • "char_filter": ["html_strip"] → HTML 태그 제거
  • "tokenizer": "standard" → 기본 토큰화
  • "filter": ["lowercase", "stop"] → 소문자 변환, 불용어(stopword) 제거

🔹 Analyzer 변경 가능 여부

  • 애널라이저 설정(analysis)은 변경 불가능
  • 변경하려면 인덱스를 close → 설정 변경 → 다시 open 해야 함

📌 애널라이저 변경 방법

POST my_index/_close
PUT my_index/_settings
{
  "analysis": {
    "analyzer": {
      "new_analyzer": {
        "type": "custom",
        "tokenizer": "whitespace"
      }
    }
  }
}
POST my_index/_open

❗ 하지만 이미 존재하는 필드의 분석 방식은 변경할 수 없음새로운 인덱스를 만들고 데이터를 다시 색인해야 함


5. 정리

설정 값 설명 변경 가능 여부
number_of_shards 인덱스의 프라이머리 샤드 개수 ❌ 변경 불가
number_of_replicas 프라이머리 샤드 당 복제본 개수 ✅ 변경 가능
refresh_interval 색인된 데이터가 검색 가능해지는 주기 ✅ 변경 가능
analysis (Analyzer) 텍스트 분석기 설정 ❌ 변경 불가 (재색인 필요)

6. 학습 가이드

1️⃣ 샤드와 복제본 개수 설정 방법 실습
2️⃣ refresh_interval을 변경하며 색인 성능 테스트
3️⃣ 사용자 정의 애널라이저를 설정하고 분석 결과 확인
4️⃣ Analyzer 변경 불가 원리를 이해하고, 새로운 인덱스로 재색인 연습


7. 마무리

Elasticsearch의 Settings는 인덱스의 성능과 검색 효율성을 결정하는 중요한 요소입니다.
특히 샤드와 복제본 개수, Refresh Interval, 분석기 설정을 이해하고 적절히 활용하는 것이 중요합니다.

다음 학습에서는 Mappings을 활용한 필드 타입 및 데이터 구조 정의 방법을 다루겠습니다! 🚀

Elasticsearch: 범위 쿼리 (Range Query)

Elasticsearch에서는 숫자 및 날짜 데이터를 효과적으로 검색할 수 있도록 **범위 쿼리(Range Query)**를 제공합니다.
이 쿼리는 특정 범위 안에 포함되는 데이터를 찾을 때 사용되며, 가격, 날짜, 온도, 점수 등 연속적인 값(Continuous Data)을 검색하는 데 유용합니다.

이번 글에서는 Range Query의 기본 개념, 사용법, 그리고 날짜 검색을 포함한 실전 예제까지 살펴보겠습니다.


1. Range Query란?

🔹 기본 개념

  • 특정 필드의 값이 특정 범위에 포함되는 문서만 검색할 때 사용됩니다.
  • 숫자(Number), 날짜(Date), IP 주소(IP Address) 등의 필드에서 주로 사용됩니다.
  • 점수(score)를 계산하지 않으며, 오로지 True/False 조건만으로 필터링합니다.

2. Range Query의 기본 문법

Range Query는 아래와 같은 4가지 조건을 지원합니다.

연산자 설명
gte (Greater Than or Equal) 이상 (≥) - 특정 값보다 크거나 같은 데이터 검색
gt (Greater Than) 초과 (>) - 특정 값보다 큰 데이터 검색
lte (Less Than or Equal) 이하 (≤) - 특정 값보다 작거나 같은 데이터 검색
lt (Less Than) 미만 (<) - 특정 값보다 작은 데이터 검색

📌 예제 데이터 (phones 인덱스)

POST phones/_bulk
{"index":{"_id":1}}
{"model":"Samsung GalaxyS 5","price":475,"date":"2014-02-24"}
{"index":{"_id":2}}
{"model":"Samsung GalaxyS 6","price":795,"date":"2015-03-15"}
{"index":{"_id":3}}
{"model":"Samsung GalaxyS 7","price":859,"date":"2016-02-21"}
{"index":{"_id":4}}
{"model":"Samsung GalaxyS 8","price":959,"date":"2017-03-29"}
{"index":{"_id":5}}
{"model":"Samsung GalaxyS 9","price":1059,"date":"2018-02-25"}

(📌 위 데이터는 실제 상품과 무관한 예제 데이터입니다.)


3. 숫자 검색 (Number Range Query)

📌 예제 1: 가격(price)이 700 이상, 900 미만인 스마트폰 검색

GET phones/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 700,
        "lt": 900
      }
    }
  }
}

🔹 결과:

  • Samsung GalaxyS 6 (price: 795) ✅
  • Samsung GalaxyS 7 (price: 859) ✅

📌 설명:

  • gte: 700 → 700 이상
  • lt: 900 → 900 미만

4. 날짜 검색 (Date Range Query)

📌 예제 2: 2016년 1월 1일 이후 출시된 스마트폰 검색

GET phones/_search
{
  "query": {
    "range": {
      "date": {
        "gt": "2016-01-01"
      }
    }
  }
}

🔹 결과:

  • Samsung GalaxyS 7 (date: 2016-02-21) ✅
  • Samsung GalaxyS 8 (date: 2017-03-29) ✅
  • Samsung GalaxyS 9 (date: 2018-02-25) ✅

📌 설명:

  • gt: "2016-01-01" → 2016년 1월 1일보다 이후(>)인 데이터 검색

5. 날짜 포맷 변환 (Format 옵션 활용)

Elasticsearch는 기본적으로 **ISO8601 날짜 형식 (yyyy-MM-dd 또는 yyyy-MM-dd'T'HH:mm:ss)**을 사용합니다.
하지만 format 옵션을 사용하면 다른 날짜 형식도 검색할 수 있습니다.

📌 예제 3: 2016년 1월 1일 ~ 2018년 1월 1일 사이 출시된 스마트폰 검색

GET phones/_search
{
  "query": {
    "range": {
      "date": {
        "gt": "31/12/2015",
        "lt": "2018",
        "format": "dd/MM/yyyy||yyyy"
      }
    }
  }
}

🔹 결과:

  • Samsung GalaxyS 7 (date: 2016-02-21) ✅
  • Samsung GalaxyS 8 (date: 2017-03-29) ✅

📌 설명:

  • format: "dd/MM/yyyy||yyyy" → 31/12/2015 또는 2018 형식 허용

6. 현재 시간(now)과 상대적 날짜 검색

Elasticsearch에서는 now 키워드를 사용하여 현재 시간을 기준으로 상대적인 날짜를 검색할 수 있습니다.

📌 예제 4: 2016년 1월 1일 이후 + 6개월 ~ 현재(now) 기준 1년 전 사이 검색

GET phones/_search
{
  "query": {
    "range": {
      "date": {
        "gt": "2016-01-01||+6M",
        "lt": "now-365d"
      }
    }
  }
}

🔹 결과:

  • Samsung GalaxyS 8 (date: 2017-03-29) ✅
  • Samsung GalaxyS 9 (date: 2018-02-25) ✅

📌 설명:

  • "2016-01-01||+6M" → 2016년 1월 1일 이후 6개월 후
  • "now-365d" → 현재 시간(now) 기준 1년 전

7. Range Query의 특징 및 제한사항

점수(score)를 계산하지 않음

  • range 쿼리는 정확성(True/False)만 확인하고 점수를 계산하지 않습니다.
  • 검색 결과는 _score: 1.0으로 동일합니다.

점수를 조정하고 싶다면 Function Score Query 활용

  • 예를 들어, 나이가 채용 조건(24~55세)과 가까울수록 높은 점수를 부여하고 싶다면 Function Score Query를 사용해야 합니다.

📌 Function Score Query 예제 (추후 학습 필요)

GET jobs/_search
{
  "query": {
    "function_score": {
      "query": {
        "range": {
          "age": {
            "gte": 24,
            "lte": 55
          }
        }
      },
      "functions": [
        {
          "gauss": {
            "age": {
              "origin": 35,
              "scale": 10
            }
          }
        }
      ]
    }
  }
}

🔹 설명: 35세를 기준으로 점수를 조정 (추후 학습 필요)


8. 정리

개념 설명
Range Query 숫자, 날짜, IP 주소 등의 범위를 검색하는 쿼리
gte / gt 이상(≥), 초과(>)
lte / lt 이하(≤), 미만(<)
Format 옵션 날짜 포맷 변경 가능
now 키워드 현재 시간 기준 검색 가능
Function Score Query 기준점에 따라 점수를 조정하고 싶을 때 사용

9. 학습 가이드

1️⃣ Range Query의 숫자 및 날짜 검색 실습
2️⃣ Format 옵션을 사용하여 다양한 날짜 포맷 테스트
3️⃣ now, +6M, -365d 같은 상대적 날짜 검색 연습
4️⃣ Function Score Query 학습 (추후 검색 점수 조정 시 활용 가능)


다음 학습에서는 Function Score Query를 활용한 검색 결과 가중치 조정 방법을 다루겠습니다! 🚀

Elasticsearch: 정확값 쿼리 (Exact Value Query)

Elasticsearch에서는 **풀 텍스트 검색(Full-Text Search)**과는 다르게 정확한 값(Exact Value)을 검색하는 방식도 지원합니다. 이 방식을 활용하면 특정 값과 정확히 일치하는 문서만 조회할 수 있으며, 검색 **점수(score)**가 계산되지 않기 때문에 빠른 검색 속도를 보장할 수 있습니다. 이번 글에서는 정확값 검색이란 무엇인지, 그리고 이를 구현하는 filter, keyword, range 쿼리에 대해 알아보겠습니다.


1. 정확값(Exact Value) 검색이란?

🔹 기본 개념

  • 풀 텍스트 검색은 **검색어와 문서의 연관성(relevancy)**을 계산하여 가장 관련성이 높은 결과를 반환합니다.
  • 하지만 정확값 검색정확히 일치하는 값을 찾는 방식이며, 점수(score)를 계산하지 않습니다.
  • 대표적인 쿼리로는 term, range 쿼리가 있으며, bool 쿼리의 filter 절에서 주로 사용됩니다.

🔹 RDBMS와 비교

RDBMS에서 WHERE column = '값' 같은 조건을 사용하여 정확히 일치하는 데이터만 조회하는 것과 비슷합니다.

📌 예제

검색어 풀 텍스트 검색 (match) 정확값 검색 (term)
fox "The quick brown fox" ✅ "fox" 단독으로 포함된 문서만 ✅
Brown fox brown dog "brown"과 "fox"를 포함한 모든 문서 "Brown fox brown dog"와 정확히 일치하는 문서 ✅

2. Bool 쿼리의 Filter 사용

🔹 Filter의 특징

  • 검색 점수(score)에 영향을 주지 않음
  • 쿼리 캐싱을 활용하여 성능 최적화
  • 정확한 값을 필터링할 때 주로 사용

📌 예제 1: match 쿼리 vs filter 쿼리

① match 쿼리 (연관성 기반 검색)

GET my_index/_search
{
  "query": {
    "match": {
      "message": "fox"
    }
  }
}

🔹 결과:

  • "The quick brown fox jumps over the lazy dog" 🆙 (연관성이 높은 문서가 우선 노출됨)
  • "The quick brown fox"

② match 쿼리 + bool must (여러 조건 검색, 점수 적용됨)

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "message": "fox" } },
        { "match": { "message": "quick" } }
      ]
    }
  }
}

🔹 결과:

  • "fox"와 "quick"이 포함된 문서만 검색되며, 점수가 반영됨

③ must + filter 조합 (정확값 필터링, 점수 미반영)

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "message": "fox" } }
      ],
      "filter": [
        { "match": { "message": "quick" } }
      ]
    }
  }
}

🔹 결과 비교

  • "fox"를 포함한 모든 문서 중 "quick"이 포함된 문서만 반환됨
  • 하지만 점수(score)는 변화 없음

3. Filter 내부에서 must_not 사용

  • 특정 단어가 포함되지 않은 문서를 찾을 때 사용
  • 점수에 영향을 주지 않으며, 빠르게 검색 가능

📌 예제 2: "fox" 포함 & "dog" 제외

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "message": "fox" } }
      ],
      "filter": [
        {
          "bool": {
            "must_not": [
              { "match": { "message": "dog" } }
            ]
          }
        }
      ]
    }
  }
}

🔹 결과:

  • "fox"가 포함된 문서 중 "dog"가 포함되지 않은 문서만 검색됨
  • 점수(score)는 변화 없음

4. Keyword 타입을 활용한 정확값 검색

🔹 Keyword 타입이란?

  • keyword 필드는 분석되지 않는(Analyzed X) 문자열 필드
  • 검색어가 정확히 일치하는 데이터만 반환
  • 대소문자, 공백까지 동일해야 검색됨
  • filter 절과 함께 사용하면 빠르게 검색 가능

📌 예제 3: keyword 필드 검색

GET my_index/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "message.keyword": "Brown fox brown dog"
          }
        }
      ]
    }
  }
}

🔹 결과:

  • "Brown fox brown dog"와 완벽하게 일치하는 문서만 반환됨
  • 점수(score)는 _score: 0.0 (점수 계산 없음)

📌 Keyword 필드의 특성
빠른 검색 속도
정확한 값 비교
대소문자 및 공백 차이까지 구분


5. Filter를 활용한 성능 최적화

filter는 점수를 계산하지 않기 때문에 성능이 우수합니다.
filter 내부의 조건들은 캐싱되므로 반복적인 검색 시 더 빠르게 실행됩니다.
숫자 범위(range) 검색이나 정확한 값(term) 검색은 filter를 사용하는 것이 유리합니다.

📌 filter 절을 사용해야 하는 경우
1️⃣ 상품 검색에서 제조사, 브랜드, 가격 필터링
2️⃣ 로그 검색에서 날짜 범위 필터링
3️⃣ ID 기반 검색에서 정확한 ID 값을 찾을 때


6. 정리

개념 설명
풀 텍스트 검색 (match) 연관성을 기준으로 검색 결과 정렬
정확값 검색 (Exact Value) 값이 정확히 일치하는 문서만 검색
Bool Query - Filter 검색 점수를 계산하지 않고 문서를 필터링
Must vs Filter must는 점수를 반영하지만, filter는 점수를 무시
Keyword 필드 분석되지 않는 문자열 필드, 정확한 검색 가능
Must Not (필터 내부 사용) 특정 단어가 포함되지 않은 문서 검색

7. 학습 가이드

1️⃣ Bool Query의 filter 절을 실습하여 정확값 검색 연습
2️⃣ Match vs Term 쿼리의 차이점을 비교하며 성능 테스트
3️⃣ Keyword 타입을 사용하여 필터링 적용
4️⃣ Range, Term, Exists 쿼리를 활용한 검색 최적화


8. 마무리

Elasticsearch에서 정확한 값을 검색할 때는 풀 텍스트 검색이 아닌 filter 기반 검색을 사용하는 것이 성능적으로 더 유리합니다.
특히 상품 검색, 로그 분석, ID 조회 등의 경우 filter와 keyword 필드를 적극 활용하면 더 빠르고 정확한 검색을 할 수 있습니다.

다음 학습에서는 Range Query를 활용한 숫자 및 날짜 범위 검색 방법을 다루겠습니다! 🚀

Bool Query (복합 쿼리) 개요

  • 여러 개의 검색 조건을 조합하여 복합적인 검색을 수행할 수 있는 강력한 쿼리 방식입니다.
  • SQL의 AND, OR, NOT과 유사하지만 완전히 동일하지 않음 → 단항 연산자로 적용됨.

Bool Query 구성 요소

키워드 설명
must 쿼리가 **참(True)**인 문서를 검색 (AND 조건)
must_not 쿼리가 **거짓(False)**인 문서를 검색 (NOT 조건)
should 일치하는 문서의 점수(Score)를 증가 (OR 조건과 유사)
filter 쿼리가 **참(True)**인 문서를 검색하되, 점수를 계산하지 않음 (빠름 & 캐싱 가능)
  • SQL과 비교
    • must ≈ AND
    • must_not ≈ NOT
    • should ≈ OR (점수 영향)
    • filter ≈ WHERE (점수 없음, 성능 최적화)

Bool Query 기본 문법

GET <인덱스명>/_search
{
  "query": {
    "bool": {
      "must": [
        { <쿼리> }
      ],
      "must_not": [
        { <쿼리> }
      ],
      "should": [
        { <쿼리> }
      ],
      "filter": [
        { <쿼리> }
      ]
    }
  }
}
  • 각 키워드(must, must_not, should, filter) 안에는 여러 개의 조건을 배열 형식으로 입력 가능.

Bool Query 사용법

예제 1: "quick" 포함 + "lazy dog" 문장 포함 (AND 조건)

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "message": "quick" } },
        { "match_phrase": { "message": "lazy dog" } }
      ]
    }
  }
}
  • "quick" 단어가 포함된 문서 + "lazy dog" 문장이 포함된 문서 검색
  • 결과: "quick"과 "lazy dog"을 포함하는 문서 검색됨

예제 2: "quick" 또는 "lazy dog" (OR 조건 유사)

GET my_index/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "message": "quick" } },
        { "match_phrase": { "message": "lazy dog" } }
      ],
      "minimum_should_match": 1
    }
  }
}
  • should 사용 → "quick" 또는 "lazy dog" 중 하나라도 포함하면 검색됨
  • minimum_should_match: 1 → 최소 하나의 조건을 만족하는 문서 포함
  • 결과: "quick" 또는 "lazy dog" 중 하나라도 포함된 문서 검색됨

예제 3: "quick" & "lazy dog" 제외 (NOT 조건)

GET my_index/_search
{
  "query": {
    "bool": {
      "must_not": [
        { "match": { "message": "quick" } },
        { "match_phrase": { "message": "lazy dog" } }
      ]
    }
  }
}
  • "quick"과 "lazy dog"이 포함되지 않은 문서만 검색
  • 결과: "quick"과 "lazy dog"이 없는 문서 반환됨

예제 4: 특정 단어 포함 (must) + 특정 단어 제외 (must_not)

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "message": "fox" } }
      ],
      "must_not": [
        { "match": { "message": "lazy" } }
      ]
    }
  }
}
  • "fox" 포함 & "lazy" 제외
  • 결과: "fox"가 있는 문서 중 "lazy"가 없는 문서 검색됨

예제 5: 특정 단어 포함 (filter) - 점수 계산 없음

GET my_index/_search
{
  "query": {
    "bool": {
      "filter": [
        { "match": { "message": "fox" } }
      ]
    }
  }
}
  • "fox"가 포함된 문서를 검색하지만, 점수(Score)를 계산하지 않음 → 빠름
  • must와 비교하면 성능이 더 우수 (검색 결과가 많을수록 차이 커짐)

Bool Query와 SQL 비교

SQL 조건 Bool Query 변환
A AND B must: [A, B]
A OR B should: [A, B], "minimum_should_match": 1
NOT A must_not: [A]
(A OR B) AND (NOT C) must: [should: [A, B]], must_not: [C]

예제 6: SQL 스타일 변환

  • SQL 스타일
    (A OR B) AND (NOT C)
    
  • Bool Query 변환
    GET my_index/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "bool": {
                "should": [
                  { "match": { "message": "A" } },
                  { "match": { "message": "B" } }
                ],
                "minimum_should_match": 1
              }
            }
          ],
          "must_not": [
            { "match": { "message": "C" } }
          ]
        }
      }
    }
    

Bool Query 정리

키워드 설명 예제
must AND 조건 "must": [{ "match": { "message": "quick" } }]
must_not NOT 조건 "must_not": [{ "match": { "message": "lazy" } }]
should OR 조건 "should": [{ "match": { "message": "quick" } }, { "match": { "message": "dog" } }], "minimum_should_match": 1
filter 점수 계산 없이 검색 "filter": [{ "match": { "message": "fox" } }]

🎯 추가 학습 추천

  1. Boosting (검색 결과 가중치 조절)
  2. Nested Query (중첩된 JSON 문서 검색)
  3. Function Score Query (점수 조작)
  4. Aggregations (데이터 그룹화 및 통계 분석)

 

Full Text Query 개요

  • Elasticsearch는 강력한 풀 텍스트 검색 기능을 제공하며, 다양한 쿼리 방식이 있습니다.
  • 주요 쿼리 종류
    • match_all: 전체 문서 검색
    • match: 부분 일치 검색 (OR / AND 조건 가능)
    • match_phrase: 순서 포함 정확한 구문 검색
    • query_string: 복잡한 검색 연산자 지원

예제 데이터 입력

  • my_index 인덱스에 _bulk API를 사용하여 데이터 입력
POST my_index/_bulk
{"index":{"_id":1}}
{"message":"The quick brown fox"}
{"index":{"_id":2}}
{"message":"The quick brown fox jumps over the lazy dog"}
{"index":{"_id":3}}
{"message":"The quick brown fox jumps over the quick dog"}
{"index":{"_id":4}}
{"message":"Brown fox brown dog"}
{"index":{"_id":5}}
{"message":"Lazy jumping dog"}
  • message 필드에 다양한 단어가 포함된 문서 5개 입력됨

match_all 쿼리 (모든 문서 검색)

쿼리 없이 실행하면 match_all 적용

GET my_index/_search

명시적으로 match_all 사용

GET my_index/_search
{
  "query": {
    "match_all": {}
  }
}
  • 모든 문서를 검색
  • hits.total.value에 검색된 문서 개수가 표시됨

match 쿼리 (부분 일치 검색)

"dog" 포함 문서 검색

GET my_index/_search
{
  "query": {
    "match": {
      "message": "dog"
    }
  }
}
  • "dog" 단어가 포함된 모든 문서 검색
  • 결과: 4개 문서 검색됨 (_id: 2, 3, 4, 5)

여러 개의 검색어 (OR 조건)

GET my_index/_search
{
  "query": {
    "match": {
      "message": "quick dog"
    }
  }
}
  • "quick" 또는 "dog" 중 하나라도 포함된 문서를 검색
  • 결과: 5개 문서 검색됨 (_id: 1, 2, 3, 4, 5)

여러 개의 검색어 (AND 조건)

  • operator: "and" 옵션을 사용
GET my_index/_search
{
  "query": {
    "match": {
      "message": {
        "query": "quick dog",
        "operator": "and"
      }
    }
  }
}
  • "quick"과 "dog"을 모두 포함하는 문서만 검색
  • 결과: 2개 문서 검색됨 (_id: 2, 3)

5. match_phrase 쿼리 (정확한 구문 검색)

"lazy dog" 검색

GET my_index/_search
{
  "query": {
    "match_phrase": {
      "message": "lazy dog"
    }
  }
}
  • **"lazy dog"**이라는 정확한 문장이 포함된 문서 검색
  • 결과: 1개 문서 검색됨 (_id: 2)

match_phrase + slop 옵션 (단어 간격 허용)

GET my_index/_search
{
  "query": {
    "match_phrase": {
      "message": {
        "query": "lazy dog",
        "slop": 1
      }
    }
  }
}
  • 설명
    • "lazy dog" 사이에 다른 단어가 1개까지 허용
    • "lazy jumping dog" 문장도 검색됨
  • 결과: 2개 문서 검색됨 (_id: 2, 5)
  • 추가 설정 가능
    • slop: 2 → "lazy jumping brown dog" 같은 문장도 검색 가능

query_string 쿼리 (복잡한 검색)

  • 루씬(Lucene) 문법을 활용한 고급 검색
  • 연산자 사용 가능 (AND, OR, NOT)
  • 필드 지정 가능 (default_field)

"lazy" AND "jumping" OR "quick dog" 검색

GET my_index/_search
{
  "query": {
    "query_string": {
      "default_field": "message",
      "query": "(jumping AND lazy) OR \"quick dog\""
    }
  }
}
  • "lazy"와 "jumping"을 모두 포함하거나 "quick dog" 문장을 포함하는 문서 검색
  • 결과: 2개 문서 검색됨 (_id: 3, 5)

Full Text Query 정리

쿼리 유형 설명 예제
match_all 모든 문서 검색 { "query": { "match_all": {} } }
match 부분 일치 검색 (OR) { "query": { "match": { "message": "dog" } } }
match (AND 조건) "quick"과 "dog"을 모두 포함 { "query": { "match": { "message": { "query": "quick dog", "operator": "and" } } } }
match_phrase "lazy dog" 문장 검색 { "query": { "match_phrase": { "message": "lazy dog" } } }
match_phrase + slop "lazy dog" 사이에 1개 단어 허용 { "query": { "match_phrase": { "message": { "query": "lazy dog", "slop": 1 } } } }
query_string 복잡한 검색 연산자 지원 { "query": { "query_string": { "default_field": "message", "query": "(jumping AND lazy) OR \"quick dog\"" } } }

🎯 추가 학습 추천

  1. bool 쿼리 (복합 조건 검색)
  2. term 쿼리 (정확한 단어 검색)
  3. wildcard & regex 검색
  4. fuzzy 검색 (오타 교정 검색)

 

Search API 개요

  • Elasticsearch의 **가장 핵심적인 기능은 검색(Querying)**입니다.
  • _search API는 인덱스 단위로 검색을 수행합니다.
  • 기본 사용법:
    GET <인덱스명>/_search
    
    • 쿼리를 입력하지 않으면 **모든 문서(match_all)**를 검색합니다.

URI 검색

  • _search?q=검색어 형식으로 간단한 검색이 가능합니다.
  • URI 검색의 장점
    • 웹 브라우저 주소창에서도 쉽게 사용 가능
    • 단순 검색에 적합

예제 1: 전체 인덱스에서 "value" 검색

GET test/_search?q=value
  • 결과 (hits.total.value에 검색된 문서 개수 표시)
    {
      "hits": {
        "total": { "value": 1 },
        "hits": [ {...} ]
      }
    }
    

예제 2: "value" AND "three" 검색

GET test/_search?q=value AND three
  • 설명
    • AND, OR, NOT 연산자 사용 가능 (대문자로 입력해야 함)
    • "value"와 "three"를 모두 포함하는 문서 검색

예제 3: 특정 필드에서 검색

GET test/_search?q=field:value
  • 설명
    • field 필드에서 "value"를 검색

URI 검색의 한계

  • 복잡한 검색 불가능 (예: 여러 개의 필드 조합, 필터링)
  • Query DSL보다 기능이 제한적
  • 권장: 단순 검색에만 사용하고, 복잡한 검색은 Query DSL 사용

데이터 본문(Data Body) 검색

  • Elasticsearch의 Query DSL을 이용한 검색 방식
  • JSON 형식의 검색 쿼리를 사용하며, 보다 강력한 검색 기능 제공

예제 1: match 쿼리 (기본 검색)

GET test/_search
{
  "query": {
    "match": {
      "field": "value"
    }
  }
}
  • 설명
    • "field" 필드에서 "value"를 검색
    • match 쿼리자연어 검색에 적합 (부분 일치 가능)

예제 2: match_all (전체 문서 조회)

GET test/_search
{
  "query": {
    "match_all": {}
  }
}
  • 설명: 모든 문서를 검색 (특정 조건 없이 전체 조회)

예제 3: 특정 필드에서 여러 키워드 검색

GET test/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "field1": "value1" } },
        { "match": { "field2": "value2" } }
      ]
    }
  }
}
  • 설명
    • "field1"에서 "value1"을 찾고
    • "field2"에서 "value2"도 함께 검색
    • AND 조건 검색

멀티테넌시 (Multitenancy)

  • 여러 개의 인덱스를 한 번에 검색할 수 있음
  • **주로 로그 데이터 분석(Log Analysis)**에 사용됨

예제 1: 쉼표(,)로 여러 인덱스 검색

GET logs-2018-01,logs-2018-02/_search
  • "logs-2018-01" 과 "logs-2018-02" 인덱스에서 검색

예제 2: 와일드카드(*)를 이용한 다중 인덱스 검색

GET logs-2018-*/_search
  • "logs-2018-"로 시작하는 모든 인덱스에서 검색

예제 3: 모든 인덱스에서 검색 (_all)

GET _all/_search
  • ⚠ 주의: _all은 시스템 부하를 초래할 수 있음
    • Elasticsearch 클러스터 내의 모든 인덱스를 검색하므로, 대량 데이터 환경에서는 권장되지 않음
    • 특정 인덱스 패턴을 지정하는 것이 좋음

Search API 정리

기능 방법 예제
전체 검색 (match_all) Query DSL GET test/_search {"query": {"match_all": {}}}
단순 검색 (URI 검색) _search?q=검색어 GET test/_search?q=value
특정 필드 검색 _search?q=필드:검색어 GET test/_search?q=field:value
match 쿼리 (부분 검색 가능) Query DSL GET test/_search {"query": {"match": {"field": "value"}}}
AND 조건 검색 URI 검색 GET test/_search?q=value AND three
여러 개의 인덱스 검색 (쉼표) _search GET logs-2018-01,logs-2018-02/_search
여러 개의 인덱스 검색 (와일드카드) _search GET logs-2018-*/_search
모든 인덱스 검색 (_all) _search GET _all/_search

🎯 추가 학습 추천

  1. 복합 쿼리(Query DSL - bool 쿼리)
    • 필터링과 랭킹을 조합한 강력한 검색 방식
  2. 검색 결과 정렬 및 페이징 (from, size)
  3. 어그리게이션(Aggregation) 사용법
  4. Highlighting (검색어 하이라이트)

 

+ Recent posts