학습 목표
mapping이 document 필드의 타입·분석 방식을 정의함을 설명할 수 있다.
text와 keyword의 차이와 언제 무엇을 쓰는지 선택할 수 있다.
dynamic mapping과 explicit mapping의 트레이드오프를 설명할 수 있다.
analyzer가 character filter·tokenizer·token filter로 term을 만드는 과정을 설명할 수 있다.
로그·이벤트용 index mapping 초안을 작성할 수 있다.
문제 상황
- 2편에서
message를 넣었는데 집계하려니Text fields are not optimised for operations— text vs keyword order_id가 문자열로 들어와 정렬·range가 이상 — dynamic mapping이 long 대신 text로 잡음GET /logs/_search에level: ERROR넣었는데 안 맞음 —error로 소문자 분석됐거나 필드 타입 불일치- mapping 없이 index 만들다 디스크 2배 — 모든 string이 text + keyword multi-field로 잡힘 (7.x+
text기본) - grok으로 뽑은
trace_id에 부분 검색이 필요 없는데 analyzed — keyword여야 함 - Kibana에서
service.keyword와service둘 다 보임 — multi-field 구조를 모름
앞 편에서 document·inverted index·NRT를 봤다. 이번 편은 필드가 어떻게 인덱싱·검색되는지 — mapping과 analyzer. Query DSL은 4편, index template은 14편이다.
1. Mapping이란?
mapping — index의 스키마에 가깝다. 각 필드의 data type과 분석(analyze) 여부를 정한다.

- field — document JSON의 키 (
level,message,@timestamp) - mapping — 필드별 type (
keyword,text,date,long…) - index time — document 적재 시 mapping에 따라 inverted index·doc values 생성
- mapping 변경은 제한적 — 타입 변경은 보통 reindex (새 index +
_reindex)
| 개념 | 설명 |
|---|---|
| properties | object 하위 필드 정의 |
| multi-field | 한 필드에 text + keyword 서브필드 |
| dynamic | 새 필드 자동 mapping (true / false / strict) |
| meta | _meta에 설명·팀 정보 (검색 영향 없음) |
GET /app-logs/_mapping
- mapping은 index(또는 data stream backing index) 단위
- 14편 composable index template으로 배포 전 고정하는 것이 프로덕션 패턴
2. text vs keyword
가장 자주 틀리는 구분.

| text | keyword | |
|---|---|---|
| 분석 | analyzer로 term 분리 | 통째로 하나의 term |
| 검색 | full-text (match) |
정확 일치·term query |
| 집계·정렬 | 기본 불가 (fielddata 비권장) | doc values로 가능 |
| 예 | message, stack_trace |
level, service, trace_id |
| inverted index | term마다 posting | 전체 문자열 하나 |
- 로그
message→ text (본문 검색)level,service,host.name→ keyword (필터·집계)order_id·trace_id→ keyword (정확 매칭; 숫자만이면long)
text+.keywordsub-fieldmessage는 검색용 text,message.keyword는 정확 집계용 — 필요할 때만 (디스크 비용)
// code/logs-mapping.example.json (발췌)
{
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"level": { "type": "keyword" },
"service": { "type": "keyword" },
"trace_id": { "type": "keyword" },
"order_id": { "type": "long" },
"message": { "type": "text" }
}
}
}
- Kibana Terms 집계는 almost always keyword 필드
3. Dynamic vs Explicit Mapping

Dynamic mapping
- 첫 document 적재 시 ES가 필드 타입 추론
- string →
text+keywordsub-field (기본 템플릿) - 숫자 →
long/double 2026-07-19형태 →date
- string →
- 장점 — 빠른 PoC, 스키마 미정 로그
- 단점 — 첫 값이 잘못되면 타입 고정 (
"001"→ keyword, 나중에 숫자 불가) dynamic: strict— 미정의 필드 거부 (프로덕션 권장에 가깝다)
Explicit mapping
- index 생성 시 mapping 선언
PUT /app-logs-000001
{
"mappings": {
"dynamic": "strict",
"properties": {
"@timestamp": { "type": "date" },
"level": { "type": "keyword" },
"message": { "type": "text" }
}
}
}
| Dynamic | Explicit | |
|---|---|---|
| 속도 | 빠른 시작 | 설계·리뷰 필요 |
| 예측성 | 낮음 | 높음 |
| 프로덕션 | PoC·dev | 권장 |
| 변경 | 필드 추가는 쉬움, 타입 변경 어려움 | template 버전 관리 |
- data stream + index template — 9·14편에서 롤오버마다 동일 mapping
4. Analyzer
analyzer — text 필드 문자열을 term으로 바꾸는 파이프라인 (2편 inverted index 입력).

"The Payment TIMEOUT!" → char filter → tokenizer → token filter → the, payment, timeout
| 단계 | 역할 | 예 |
|---|---|---|
| Character filter | 문자 정규화 | HTML strip, & → and |
| Tokenizer | 문자열 → 토큰 | standard (공백·구두점), whitespace |
| Token filter | 토큰 가공 | lowercase, stop, stemmer, synonym |
기본·커스텀
# 내장 analyzer 테스트
GET /_analyze
{
"analyzer": "standard",
"text": "The Payment TIMEOUT!"
}
# tokens: the, payment, timeout
// code/custom-analyzer.example.json
{
"settings": {
"analysis": {
"analyzer": {
"log_message": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "asciifolding"]
}
}
}
},
"mappings": {
"properties": {
"message": { "type": "text", "analyzer": "log_message" }
}
}
}
standard— 대부분 로그 메시지 기본값으로 충분- 한국어 —
noritokenizer·decompound (별도 플러그인·설정) - search_analyzer — index 시 analyzer와 검색 시 analyzer 분리 (동의어·stemming)
- keyword 필드 — analyzer 없음
| 용도 | analyzer 힌트 |
|---|---|
| 영문 로그 | standard + lowercase |
| 코드·ID 혼재 message | 과도한 stemming 지양 |
| 도메인 동의어 | synonym filter (검색 품질) |
| URL·path | keyword 또는 pattern tokenizer |
5. 자주 쓰는 필드 타입
| type | 용도 | 로그 예 |
|---|---|---|
| date | 시간·range | @timestamp |
| keyword | enum·ID·집계 | level, trace_id |
| text | full-text | message, stack_trace |
| long / double | 수치 | duration_ms, status |
| boolean | 플래그 | success |
| ip | IP | client.ip |
| object | 중첩 JSON | kubernetes.labels |
| nested | object 배열 독립 검색 | items[] (배열 요소별 매칭) |
| flattened | 동적 키 많을 때 | debug map (키 제한 주의) |
object— 내부 필드 평탄화; 배열 object는 교차 매칭 위험 →nested- ECS(Elastic Common Schema) — 필드명·타입 표준 (Fleet integration이 ECS 사용)
6. 로그 mapping 설계 습관
| 습관 | 이유 |
|---|---|
@timestamp date |
Kibana time field |
| 차원 필드 keyword | filter·aggregation |
| 본문만 text | 디스크·집계 분리 |
| dynamic: strict (prod) | 예기치 않은 필드 폭발 방지 |
| ignore_above on keyword | 초장문 깨짐 방지 (기본 256) |
| mapping을 template으로 | 14편 ILM 롤오버와 연동 |
PUT /_index_template/app-logs-template
{
"index_patterns": ["app-logs-*"],
"template": {
"mappings": {
"dynamic": "strict",
"properties": {
"@timestamp": { "type": "date" },
"level": { "type": "keyword" },
"service": { "type": "keyword" },
"message": { "type": "text" }
}
}
},
"priority": 200
}
- ingest pipeline에서 필드 정규화 후 strict mapping — 8편
- 잘못된 mapping 발견 시 — 새 index + reindex (20편 운영)
7. 실무에서 기억할 점
| 증상 | 원인 | 조치 |
|---|---|---|
집계 불가 on message |
text | keyword 필드 또는 .keyword |
order_id 정렬 이상 |
text로 매핑됨 | long + reindex |
| 검색 대소문자 안 맞음 | keyword에 analyzer 적용 기대 | match on text vs term on keyword |
| 필드 폭발 | dynamic true | strict + template |
| 한글 검색 약함 | standard analyzer | nori 등 언어 analyzer |
- 4편 —
matchvstermvskeywordfilter in Query DSL - 5편 — aggregation이 doc values에 의존
정리
- mapping — 필드 타입·분석 규칙; 로그는 keyword 차원 + text 본문
- text — analyzed, full-text; keyword — exact, 집계·정렬
- dynamic — PoC용; explicit + strict — 프로덕션
- analyzer — character filter → tokenizer → token filter → terms
- 14편 — index template으로 mapping 표준화
다음에 다룰 것
- Query DSL
- match, bool, filter, pagination, search_after
해당 내용은 Elasticsearch Guide (Mapping, Text analysis) 를 기반으로 합니다.
'ELK & Elastic Cloud' 카테고리의 다른 글
| Beats (0) | 2026.07.11 |
|---|---|
| Aggregation과 클러스터 (0) | 2026.07.08 |
| Query DSL (0) | 2026.07.05 |
| Elasticsearch란 (0) | 2026.07.02 |
| ELK · Elastic Cloud 오리엔테이션 (0) | 2026.06.30 |