4 분 소요

[ELK Stack]Elasticsearch - 매핑,스키마,템플릿

1. 매핑이란?

RDB에서는 테이블을 만들 때 스키마 설계를 반드시 해야 함. 스키마는 테이블을 구성하는 각 컬럼의 타입, 길이, 관계 등을 정의하는 규칙임. 이 구조는 데이터 정합성과 효율적인 질의를 가능하게 함. Elasticsearch에서도 비슷한 개념이 존재하는데, 이걸 매핑(Mapping) 이라고 부름.

매핑은 JSON 형태의 도큐먼트를 Elasticsearch 내부의 Lucene이 이해할 수 있는 구조로 변환하는 일종의 스키마 정의임. 검색엔진으로서 Elasticsearch가 대용량 데이터를 빠르게 검색하고 실시간 분석이 가능한 이유는 이 매핑 구조 덕분임. 매핑을 제대로 정의해놓으면 성능은 물론 검색 정확도, 집계 효율성까지 크게 향상됨.

  • 자동 매핑: 다이나믹 매핑 (Elasticsearch가 알아서 매핑)
  • 수동 매핑: 명시적 매핑 (사용자가 직접 매핑 정의)

2. 다이나믹 매핑

다이나믹 매핑은 데이터를 인덱싱할 때 Elasticsearch가 자동으로 필드 타입을 추론하여 매핑을 생성하는 기능임. 즉, 사용자가 따로 매핑을 지정하지 않아도 기본적인 구조를 판단해서 알아서 설정해줌.

예시로는

PUT index_auto/_doc/1
{
  "name": "pcy",
  "age": 27,
  "is_active": true,
  "joined": "2024-01-01",
  "tags": ["engineer", "dev"]
}

해당 도큐먼트를 넣으면 자동으로 다음과 같이 매핑이 생성됨:

"properties": {
  "name": {"type": "text"},
  "age": {"type": "long"},
  "is_active": {"type": "boolean"},
  "joined": {"type": "date"},
  "tags": {"type": "text"}
}

자동 매핑은 편리하지만, 잘못된 타입으로 인덱싱되면 성능 저하나 쿼리 오류를 유발할 수 있음. 따라서 초기에 테스트 환경에서 매핑 결과를 확인하고, 정식 환경에서는 명시적 매핑을 권장함.

다이나믹 매핑의 타입 추론 기준표

JSON 데이터 타입 Elasticsearch 매핑 타입 (dynamic: true)
null 필드 없음 (매핑 안함)
true/false boolean
double float 또는 double
long long
object object
array 배열 내부 첫 번째 값의 타입 따름
문자열(date 추정) date
문자열(숫자 추정) long 또는 float
일반 문자열 text + keyword

※ 배열은 내부 값이 null인 경우 필드 자체가 무시됨 ※ 문자열 타입은 내부 룰에 따라 날짜/숫자로도 자동 판별될 수 있음


3. 매핑 조회 예시

GET index2/_mapping
"properties": {
  "age": {"type": "long"},
  "name": {"type": "text", "fields": {"keyword": {"type": "keyword"}}},
  "gender": {"type": "text", "fields": {"keyword": {"type": "keyword"}}},
  "country": {"type": "text", "fields": {"keyword": {"type": "keyword"}}}
}

근데?

  • age: 일반적으로 200세 넘는 사람은 없기 때문에 short 타입으로 설정 가능 → 공간 절약 + 성능 향상
  • gender, country: 집계, 정렬 용도면 keyword 타입으로 변경 권장 → 불필요한 분석기 오버헤드 방지

4. 명시적 매핑 (Explicit Mapping)

매핑을 사전에 정의해서 인덱스를 생성하는 방식임. 대용량 데이터를 다루거나, 필드 타입을 엄격하게 통제해야 하는 환경에서는 필수적임.

PUT index_explicit
{
  "mappings": {
    "properties": {
      "name":    {"type": "text"},
      "family":  {"type": "keyword"},
      "age":     {"type": "short"}
    }
  }
}
  • name: 검색 가능한 텍스트
  • family: 집계 및 정렬용
  • age: 적절한 숫자 범위로 효율화

매핑 설정에 사용되는 주요 파라미터들

파라미터 설명
type 필드의 데이터 타입
analyzer 문자열 분석기 지정
format 날짜 형식 지정 (예: yyyy-MM-dd)
index false로 설정 시 인덱싱 제외
null_value null일 때 대체값 지정
ignore_above 문자열 길이 초과 시 인덱싱 제외

5. 문자열 처리 - text vs keyword

text 타입

  • 분석기(analyzer) 를 거쳐 토큰 단위(term) 로 분리되어 역인덱싱
  • match 쿼리 등 풀텍스트 검색에 적합
  • 문장 내부의 일부분만 검색해도 매칭 가능하며, 자연어 검색에 유리함
  • 토큰 필터를 이용해 소문자 처리, 불용어 제거, 형태소 분석까지 가능

분석기 단계:

  1. 캐릭터 필터 → HTML 태그 제거 등 전처리
  2. 토크나이저 → 문장을 단어 단위로 분리 (예: cute dogcute, dog)
  3. 토큰 필터 → 소문자 변환, 불용어 제거 등

match 예제

GET index2/_search
{
  "query": {
    "match": {
      "name": "Chan Young"
    }
  }
}

keyword 타입

  • 전체 문자열이 하나의 토큰으로 취급됨 (분석기 미적용)
  • 정확히 일치하는 값 검색, 집계/정렬에 적합
  • 대소문자 구분되며, 토큰 처리가 없기 때문에 저장 공간도 절약됨

term 예제

GET index2/_search
{
  "query": {
    "term": {
      "gender.keyword": "male"
    }
  }
}

6. 멀티필드 (Multi Field)

Elasticsearch에서는 하나의 필드를 다양한 방식으로 검색/처리할 수 있게 fields 속성을 지원함. 이걸 멀티필드라고 함. 주로 textkeyword 타입을 동시에 정의할 때 활용됨.

예를 들어 contents라는 필드를 분석기 기반의 텍스트 검색과 정확 일치 기반의 집계/정렬 양쪽에서 모두 사용하고 싶다면 다음처럼 설정함.

PUT multifield_index
{
  "mappings": {
    "properties": {
      "contents": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "message": { "type": "text" }
    }
  }
}
  • contents: 기본은 text → 전문 검색용
  • contents.keyword: keyword 하위 필드 → 정렬/집계용

멀티필드를 정의해두면 아래처럼 다양한 방식으로 활용할 수 있음.

match 쿼리 (풀텍스트 검색)

GET multifield_index/_search
{
  "query": {
    "match": {
      "contents": "elasticsearch tutorial"
    }
  }
}

term 쿼리 (정확 일치 검색)

GET multifield_index/_search
{
  "query": {
    "term": {
      "contents.keyword": "elasticsearch tutorial"
    }
  }
}

집계 쿼리

GET multifield_index/_search
{
  "size": 0,
  "aggs": {
    "content_terms": {
      "terms": {
        "field": "contents.keyword"
      }
    }
  }
}

멀티필드를 통해 텍스트 분석 기반 검색과, 정확한 키워드 기반 집계/정렬을 유연하게 병행할 수 있음.


7. 인덱스 템플릿

동일한 매핑/설정을 반복해서 여러 인덱스에 적용하려면 템플릿을 사용하는 것이 효율적임. 특히 파티셔닝된 인덱스 구조에서는 필수적인 기능임.

템플릿 조회

GET _index_template
GET _index_template/ilm-history
GET _index_template/ilm*

템플릿 생성 예시

PUT _index_template/test_template
{
  "index_patterns": ["test_*"],
  "priority": 1,
  "template": {
    "settings": {
      "number_of_replicas": 1,
      "number_of_shards": 3
    },
    "mappings": {
      "properties": {
        "name": {"type": "text"},
        "age": {"type": "short"},
        "gender": {"type": "keyword"}
      }
    }
  }
}

템플릿 주요 파라미터

설명
index_patterns 어떤 인덱스에 적용할지 패턴 지정 (와일드카드 사용 가능)
priority 템플릿 우선순위 (숫자가 클수록 우선 적용)
template.settings 인덱스 설정 (샤드 수, 복제 수 등)
template.mappings 인덱스 매핑 정보

템플릿 적용 확인

PUT test_index1
GET test_index1/_mapping

test_template이 자동으로 적용된 매핑 확인 가능

우선순위가 높은 템플릿이 먼저 적용되며, 충돌 시 우선순위 기준으로 병합됨.

끄읕.

댓글남기기