Elasticsearch 입문 8편 Mapping Deep. 5분류 + Mapping Explosion 회피 + text vs keyword multi-field + Runtime Field trade-off.
이 글은 Elasticsearch 입문에서 운영까지 시리즈 38편 중 8편이에요. 1편에서 Mapping = RDBMS 스키마 자리라고 짚었고, 시리즈 다섯 글자 (Index·Document·Shard·Replica·Mapping) 중 마지막 자리. 한 번 잡으면 변경이 까다롭다 라는 문장이 1편 핵심 경고였는데, 이 글이 그 까다로운 이유 와 그래도 다루는 법 을 한 호흡에 풀어요.
이 글은 Elasticsearch 8.x 공식 docs (Mapping 챕터) 를 참고해 한국어 학습 노트로 풀어쓴 자료예요.
로컬 ES 에서 PUT /test-mapping 한 번 직접 던져 보고 GET /test-mapping/_mapping 으로 결과를 확인해 보면 본문이 훨씬 진해져요.
왜 8편이 가장 길게 다뤄지는가
시리즈 38편 중 Mapping 한 주제에만 한 편을 통째로 박는 이유는 단순해요. 사고 발생 빈도 1위가 Mapping 사고이기 때문이에요. 1편 사고 7가지 중 Mapping Explosion · Korean Tokenizer 미설정 둘이 Mapping 영역이고, 거기에 text vs keyword 혼동 · multi-field 누락 · dynamic strict 안 켜기 같은 조용한 사고 까지 합치면 운영 첫 6개월 사고의 절반 이상이 Mapping 에서 나와요.
이게 까다로운 이유 가 한 줄로 요약돼요 — 이미 색인된 필드의 타입은 바꿀 수 없어요. RDBMS 의 ALTER TABLE ... MODIFY COLUMN 같은 명령이 ES 엔 사실상 X. 바꾸려면 reindex (전체 재색인) 비용을 내야 해요. 데이터 1TB 면 그 비용이 수 시간 ~ 며칠 이라서, 운영 중에 가볍게 못 건드려요.
그래서 Mapping 설계는 처음에 잘 잡는 것 외에 다른 답이 거의 없어요. 이 글이 그 처음 을 위한 압축 매뉴얼이에요.
Mapping 의 다섯 갈래를 한 페이지로 압축하면 이래요. Static Mapping (명시적 정의) · Dynamic Mapping (자동 추론) · Dynamic Templates (자동 추론에 규칙 박기) · Multi-field (한 필드를 여러 방식으로 색인) · Runtime Field (색인 안 하고 쿼리 시점 계산). 운영 표준은 Static + Dynamic Templates + Multi-field 셋의 조합이고, Dynamic = strict 로 잠그고 Runtime Field 는 조심해서 — 이게 한 줄 결론이에요. 본문이 이 한 줄을 풀어 가요.
Static Mapping — 명시적으로 필드를 박는다
Static Mapping 은 인덱스를 만들 때 어느 필드가 어떤 타입인지 를 사람이 미리 박아 두는 방식이에요. 운영 인덱스의 표준 방식이고, Mapping Explosion 사고 와 타입 추론 실패 둘 다 막을 수 있는 유일한 길이에요.
기본 구조가 이래요.
PUT /products
{
"mappings": {
"properties": {
"product_id": { "type": "keyword" },
"name": { "type": "text", "analyzer": "nori" },
"price": { "type": "long" },
"in_stock": { "type": "boolean" },
"created_at": { "type": "date" },
"tags": { "type": "keyword" }
}
}
}
mappings.properties 아래에 필드 이름 → { type, options } 가 한 줄씩 놓여요. 핵심은 type 선언이에요. 자주 쓰는 타입을 한 호흡에 짚으면 — keyword (정확 일치·정렬·집계용 문자열) · text (풀텍스트 분석·검색용 문자열) · long·integer·short·byte (정수) · double·float·half_float (실수) · boolean · date · geo_point (위경도) · ip · dense_vector (임베딩 벡터, 22편에서 깊이) · nested (배열 내부 객체를 독립 문서처럼 색인) · object (중첩 객체 평탄 색인) — 이 정도가 핵심.
특히 text vs keyword 의 갈림 이 운영 사고의 단골 자리예요. 둘 다 문자열이지만 자리가 완전히 달라요.
- text = 형태소 분석기로 토큰화 → 풀텍스트 검색 자리. 정렬·집계·정확 일치 X. 상품 이름·블로그 본문·리뷰 자리.
- keyword = 원본 그대로 색인 → 정확 일치·정렬·집계 자리. 풀텍스트 검색 X. 상품 ID·카테고리 코드·태그·이메일 자리.
"name": "삼성전자 갤럭시 S25" 같은 필드를 검색도 하고 정렬도 하고 싶다 면, 두 가지 방식을 동시에 색인해야 해요. 이게 곧 Multi-field 패턴 (5절에서) 으로 이어져요.
운영 표준 Static Mapping 은 이런 모양이에요.
PUT /orders
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"index.mapping.total_fields.limit": 1000
},
"mappings": {
"dynamic": "strict",
"properties": {
"order_id": { "type": "keyword" },
"user_id": { "type": "keyword" },
"amount": { "type": "long" },
"currency": { "type": "keyword" },
"items": {
"type": "nested",
"properties": {
"sku": { "type": "keyword" },
"name": { "type": "text", "analyzer": "nori" },
"qty": { "type": "integer" }
}
},
"ordered_at": { "type": "date" }
}
}
}
세 가지 포인트가 박혀 있어요. ① dynamic: strict 로 예상치 못한 필드는 거부 한다. ② index.mapping.total_fields.limit 로 필드 총 개수 상한 을 박는다. ③ 배열 내부 객체는 nested 로 색인해 각 항목 단위 검색 을 보존한다 — 만약 object 로 두면 배열이 평탄화돼서 "qty=2 면서 sku=ABC 인 항목" 같은 항목 묶음 쿼리 가 안 돼요.
Dynamic Mapping — JSON 자동 추론과 그 함정
Dynamic Mapping 은 처음 본 필드를 JSON 타입에서 자동 추론해 mapping 에 박는 방식이에요. ES 의 기본 동작이고, Hello World 단계에선 편하지만 운영에선 매우 위험해요.
자동 추론 규칙이 정해져 있어요.
| JSON 값 | 추론된 ES 타입 |
|---|---|
"hello" |
text + keyword multi-field |
42 |
long |
3.14 |
float |
true |
boolean |
"2026-05-19" |
date (포맷 자동 감지) |
{ "nested": ... } |
object |
[1, 2, 3] |
long (배열 → 첫 원소 타입) |
이 규칙엔 함정이 두 개 있어요. 첫째 — 문자열이 들어오면 무조건 text + keyword 둘 다 색인 한다는 점. 색인 부피가 두 배가 돼요. 둘째 — 처음 들어온 값이 타입을 고정 한다는 점. 첫 문서가 "price": 100 (long) 인데 두 번째 문서가 "price": 99.9 (float) 면 float 값이 long 으로 강제 변환되거나 거부 돼요.
Dynamic Mapping 은 세 가지 모드 가 있어요. 인덱스 mapping 의 최상위 dynamic 키로 정해요.
dynamic: true(기본값) — 새 필드를 자동 추론해 mapping 에 추가. 가장 위험.dynamic: false— 새 필드를 색인 안 함, mapping 에도 안 추가, 거부도 안 함._source엔 남지만 검색 X. 어중간.dynamic: strict— 새 필드 들어오면 문서 자체를 거부. 운영 표준.
PUT /events
{
"mappings": {
"dynamic": "strict",
"properties": {
"event_type": { "type": "keyword" },
"user_id": { "type": "keyword" },
"occurred_at":{ "type": "date" }
}
}
}
POST /events/_doc
{
"event_type": "login",
"user_id": "u-001",
"occurred_at":"2026-05-19T10:00:00",
"ip": "10.0.0.1"
}
이 요청은 400 strict_dynamic_mapping_exception 으로 거부돼요. ip 필드가 mapping 에 정의 안 됐기 때문이에요. 조용히 색인 안 되는 것 보다 대놓고 거부 가 운영에 훨씬 좋아요 — 사고를 빨리 만나서 빨리 고친다.
Mapping Explosion 사고 시나리오
dynamic: true 가 켜진 인덱스에 임의 키 를 가진 JSON 이 들어오는 경우가 운영 사고 단골이에요. 예 — 광고 추적 로그가 광고 ID 를 필드 이름으로 박는 잘못된 스키마라 ad_001: true · ad_002: true · ad_003: true · ... 식으로 들어와요. 한 달 후 mapping 의 필드 수가 수십만 개 가 돼서 클러스터 메모리가 터져요.
이게 Mapping Explosion 의 정의예요. 8.x 기본값 index.mapping.total_fields.limit: 1000 이 1차 방벽이지만, 이 값을 모른 채 키워 놓으면 사고가 그대로 일어나요. 운영 인덱스는 dynamic: strict 가 사실상 강제.
Dynamic Templates — 자동 추론에 규칙을 박는다
Static 으론 모든 필드를 다 못 박을 때 (예 — 사용자가 정의하는 메타데이터) Dynamic Templates 가 답이에요. 조건에 맞는 동적 필드만 자동 매핑 하고 나머지는 거부하거나 무시할 수 있어요.
핵심 매칭 키가 세 가지예요. match_mapping_type 은 JSON 추론 타입 (string·long·boolean 등) 에 매칭. match 는 필드 이름 와일드카드. unmatch 는 제외 패턴.
PUT /logs
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keyword": {
"match_mapping_type": "string",
"mapping": { "type": "keyword", "ignore_above": 256 }
}
},
{
"longs_as_long": {
"match_mapping_type": "long",
"mapping": { "type": "long" }
}
},
{
"ts_fields_as_date": {
"match": "*_at",
"mapping": { "type": "date" }
}
}
]
}
}
이 인덱스는 어떤 새 필드도 받지만 규칙을 적용해요. 문자열은 keyword 로만 (text 자동 multi-field 끔) · *_at 으로 끝나는 필드는 date 로 · 그 외 정수는 long 으로. 이게 로그 인덱스 표준 패턴 이에요. Mapping Explosion 1차 방벽 + 자동 매핑 편의 둘 다 가져요.
ignore_above: 256 옵션도 중요해요. 길이 256 자 초과 문자열은 색인 안 함, _source 엔 남김. URL · 큰 JSON blob 같은 비정상 값으로 색인이 터지는 걸 막아 줘요.
운영에서 자주 쓰는 패턴 세 가지를 더 짚으면 —
{
"ip_fields": {
"match": "*_ip",
"mapping": { "type": "ip" }
}
}
*_ip 로 끝나는 필드를 IP 타입으로 자동 매핑. 서브넷 검색 ("client_ip": "10.0.0.0/8") 이 가능해져요.
{
"no_text_for_dynamic": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword",
"fields": {
"search": {
"type": "text",
"analyzer": "nori"
}
}
}
}
}
동적 문자열을 기본은 keyword · 하위 .search 로 text 인 multi-field 로 깔아요. 정확 일치·정렬·집계는 root 로, 풀텍스트 검색은 .search 로 한다.
{
"deny_object": {
"match_mapping_type": "object",
"mapping": { "type": "flattened" }
}
}
중첩 객체를 flattened 로 강제. flattened 타입은 오브젝트 전체를 한 필드로 색인 해서 Mapping Explosion 의 근본 해결 자리예요. 단점은 내부 필드별 정렬·집계 어렵다 — 이게 trade-off.
Multi-field — 한 필드를 여러 방식으로 색인하기
ES 운영에서 가장 자주 쓰는 mapping 패턴이 Multi-field 예요. fields 키로 서브 필드 를 박아 한 데이터를 여러 분석기로 동시 색인 해요.
가장 흔한 자리가 text + keyword 패턴.
PUT /articles
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "nori",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
이 mapping 으로 색인하면 한 문서가 들어올 때마다 title 이 두 갈래로 색인 돼요. ① title 은 Nori 형태소 분석기로 토큰화 → 풀텍스트 검색. ② title.keyword 는 원본 그대로 → 정확 일치·정렬·집계. 쿼리는 자리에 맞게 골라 써요.
GET /articles/_search
{
"query": {
"match": { "title": "삼성전자 신제품" }
}
}
GET /articles/_search
{
"query": {
"term": { "title.keyword": "삼성전자 갤럭시 S25" }
}
}
GET /articles/_search
{
"size": 0,
"aggs": {
"by_title": {
"terms": { "field": "title.keyword", "size": 10 }
}
}
}
세 가지 쿼리가 같은 데이터 위 에서 돌아가요. match 는 풀텍스트, term 은 정확 일치, aggs.terms 는 집계. 집계·정렬은 keyword 필드 필수 라서 multi-field 누락 사고가 자주 나요.
자주 쓰는 다른 multi-field 패턴도 짚으면 —
"title": {
"type": "text",
"analyzer": "nori",
"fields": {
"english": { "type": "text", "analyzer": "english" },
"raw": { "type": "keyword" }
}
}
한 필드를 한국어 · 영어 · 원본 keyword 세 방식으로. 한·영 혼합 콘텐츠가 많은 회사 표준.
"name": {
"type": "text",
"analyzer": "nori",
"fields": {
"ngram": {
"type": "text",
"analyzer": "ngram_analyzer"
}
}
}
검색 자동완성용 ngram 서브 필드. "갤" 만 쳐도 "갤럭시" 가 매치돼요.
"email": {
"type": "keyword",
"fields": {
"domain": {
"type": "keyword",
"normalizer": "extract_domain"
}
}
}
이메일을 root 는 원본 그대로, .domain 은 도메인만 추출 해서 색인. @naver.com 사용자 집계 가 한 번에 돼요.
Multi-field 의 핵심 주의 한 가지 — 서브 필드도 디스크·메모리를 먹어요. text + keyword 둘 다 박으면 색인 크기가 원본의 2배 가 돼요. 모든 필드에 막무가내로 박지 말고 집계·정렬·검색 자리가 명확한 필드만 깔아 두는 게 표준.
Runtime Field — 색인 안 하고 쿼리 시점에 계산
8.x 부터 본격화된 Runtime Field 는 색인 시점이 아닌 쿼리 시점에 값을 계산 해 주는 가상 필드예요. 기존 필드로부터 파생 값 을 만들 때 reindex 없이 쓸 수 있어요.
가장 흔한 자리가 이미 운영 중인 인덱스에 새 분석 자리가 생긴 경우.
PUT /orders/_mapping
{
"runtime": {
"discount_rate": {
"type": "double",
"script": {
"source": "emit((doc['original_price'].value - doc['final_price'].value) / (double) doc['original_price'].value)"
}
}
}
}
GET /orders/_search
{
"fields": ["discount_rate"],
"query": {
"range": { "discount_rate": { "gte": 0.3 } }
}
}
이 인덱스엔 원래 discount_rate 필드가 없었지만, runtime field 로 기존 두 필드의 비율 을 가상으로 만들어 쿼리·정렬·집계 까지 할 수 있어요. reindex 없이 바로 적용.
가능한 자리를 한 호흡에 짚으면 — 파생 필드 (할인율·만족도 점수·가공 카테고리) · 임시 컬럼 (캠페인 기간만 쓰는 라벨) · 데이터 수정 (오타 필드를 임시로 정정) · prototyping (정식 reindex 전 검증).
trade-off 가 두 가지예요. 첫째 — 모든 매칭 문서를 매 쿼리 시점에 스크립트로 계산 하니까 느려요. 작은 데이터에선 차이가 안 보이지만 수백만 문서 단위에선 즉시 체감돼요. 둘째 — 집계 위 정렬 같은 일부 연산은 색인 필드보다 훨씬 비효율.
운영 가이드는 단순해요. 자주 쓰면 정식 필드로 reindex, 어쩌다 쓰면 runtime field. prototype → 정식 reindex 흐름이 표준.
runtime field 폭주 사고도 있어요. 분석가가 runtime field 30개 를 깔아 두고 한 인덱스에 복잡한 스크립트 가 매 쿼리마다 돌면, 클러스터 CPU 사용률이 80%+ 로 뛰어요. 어느 runtime field 가 어디서 쓰이는지 추적하기도 어려워서, 운영 인덱스엔 최대 5개 이내 가 거친 가이드.
Mapping 변경 — 어떤 변경이 가능한가
운영 중 인덱스의 mapping 을 변경할 수 있는 것 · 없는 것 의 갈래가 명확해요.
가능한 변경 — 새 필드 추가 (PUT mapping API) · Multi-field 서브 필드 추가 · Runtime field 추가/수정/삭제 · 일부 옵션 수정 (ignore_above 같은 색인 시점에 영향 안 주는 옵션) · Dynamic Templates 추가/수정 (이미 색인된 데이터엔 영향 X, 새 데이터에만).
불가능한 변경 — 이미 색인된 필드의 타입 (text → keyword 등) · Analyzer (이미 색인된 데이터의 토큰은 이미 박혀 있어요) · Field 삭제 (직접 삭제 API X, alias 갈아끼기·_source 에서 필드 제거 정도만 가능) · Nested vs Object 변경 · Number 정밀도 축소 (long → integer 등).
불가능한 변경이 필요할 땐 reindex 흐름 하나뿐이에요.
PUT /products-v2
{
"mappings": { ... 새 mapping ... }
}
POST /_reindex
{
"source": { "index": "products-v1" },
"dest": { "index": "products-v2" }
}
POST /_aliases
{
"actions": [
{ "remove": { "index": "products-v1", "alias": "products" } },
{ "add": { "index": "products-v2", "alias": "products" } }
]
}
흐름이 4단계 예요. ① 새 mapping 의 v2 인덱스 생성. ② _reindex API 로 v1 → v2 데이터 복사. ③ alias 갈아끼기 로 앱은 v2 를 보게 함. ④ v1 인덱스 삭제.
이 흐름에서 앱은 alias products 만 알아요. 인덱스 이름이 products-v1 → products-v2 로 바뀌어도 알 필요가 X. alias-first 설계 가 운영 표준인 이유.
reindex 비용을 짚으면 — 데이터 100GB 기준 30분~2시간, 1TB 기준 8~24시간. 온라인 reindex 는 가능하지만 그 사이 들어오는 새 문서 를 어떻게 v2 에 반영할지 추가 설계가 필요해요. 흔한 패턴은 듀얼 라이트 (앱이 v1·v2 둘 다 쓰기) → reindex 완료 → alias 갈아끼기 → v1 삭제.
자주 만나는 사고 6가지
사고 1 — Mapping Explosion (반복)
원인 — dynamic: true + 임의 키 JSON. 1편에서도 짚었지만 가장 흔해요.
해결 — dynamic: strict + index.mapping.total_fields.limit: 1000. 광고 ID 같은 가변 키 는 flattened 타입으로 강제.
사고 2 — dynamic strict 안 켜기
원인 — 8.x 도 기본값이 strict 가 X. true 라서 사람이 박지 않으면 폭주가 그대로 일어나요.
해결 — 모든 운영 인덱스 mapping 의 최상위에 "dynamic": "strict" 박기. 코드 리뷰 룰로 잡아 두는 게 답.
사고 3 — Multi-field keyword 누락
원인 — name: text 만 박고 name.keyword 를 안 깔아 둔 경우. 일주일 후 분석가가 "name 별 집계 해달라" 하면 불가. reindex 비용을 내야 해요.
해결 — 문자열 필드는 거의 모두 text + keyword multi-field 로 깔아 두는 게 default. 동적 매핑 default 가 이래서 사람들이 multi-field 패턴이 익숙해진 거예요.
사고 4 — text vs keyword 혼동
원인 — category 필드를 text 로 박고 집계 가 안 돼서 당황. 또는 상품 이름 을 keyword 로 박고 부분 검색 이 안 돼서 당황.
해결 — 집계·정렬·정확 일치 = keyword, 풀텍스트 검색 = text 라는 갈래를 명확히. 둘 다 필요하면 multi-field.
사고 5 — Runtime Field 폭주
원인 — 분석가가 runtime field 를 정식 필드처럼 30개 박아 두고, 매 쿼리마다 30개 스크립트가 돌면 CPU 가 폭증.
해결 — 자주 쓰면 reindex 로 정식 필드화, 어쩌다 쓰면 runtime. 인덱스당 runtime field 5개 이내 가이드.
사고 6 — Date 포맷 자동 추론 실패
원인 — 첫 문서가 "date": "2026-05-19" (date 추론 성공) 인데, 두 번째 문서가 "date": "2026/05/19" (포맷 불일치) 라 mapper_parsing_exception 으로 거부.
해결 — date 필드는 항상 Static 으로 박고 format 옵션 명시.
"created_at": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
여러 포맷을 || 로 OR 처럼 허용할 수 있어요.
사고 7 — Nested 안 쓴 배열 객체
원인 — items 배열을 object 로 두면 내부 필드가 평탄화 돼서 "qty=2 면서 sku=ABC 인 항목" 같은 항목 단위 묶음 쿼리 가 안 돼요.
해결 — 배열 내부 객체는 거의 항상 nested. 단점은 nested 가 각 항목을 독립 문서로 색인 해서 디스크·메모리 비용이 큼 — 작은 배열은 flattened 가 답일 수도.
운영 권장 패턴 5가지
운영 인덱스 mapping 의 최상위 5계명 을 한 페이지로 압축해 둬요.
(1) Static + strict 기본. Hello World 외엔 dynamic: true 금지. 모든 운영 인덱스 mapping 최상위에 "dynamic": "strict" 박고, index.mapping.total_fields.limit 도 1000 또는 그 이하로 박는다. 예상치 못한 필드는 거부 가 조용히 색인 안 됨 보다 훨씬 안전.
(2) Dynamic Templates 로 동적 자리 만 열기. 사용자 정의 메타데이터 · 로그 · 추적 데이터처럼 진짜 동적인 자리 가 있을 땐, dynamic_templates 로 규칙 을 박아 허용 + 자동 매핑 한다. 룰 — 문자열은 keyword · *_at 은 date · *_ip 는 ip · 나머지 object 는 flattened.
(3) Multi-field 는 의미가 있는 자리만. 모든 text 에 keyword 박지 X. 정렬·집계·정확 일치 자리가 명확한 필드만 multi-field 로 깔고, 나머지는 text 단일. 색인 부피를 절반으로 줄일 수 있어요.
(4) alias-first. 앱은 실제 인덱스 이름 이 아닌 alias 로만 ES 를 본다. mapping 변경 = reindex + alias 갈아끼기 흐름이 항상 깔려 있어야 다운타임 0 으로 운영 가능.
(5) Runtime Field 는 임시 자리 라는 라벨. runtime field 5개 이내, 3개월 이상 살아 있는 runtime field 는 정식 reindex 검토. 분석가 임시 작업 · prototype · 핫픽스 자리로만.
시험 직전 한 번 더 — 압축 노트
- Mapping = RDBMS 의 스키마 자리. 한 번 색인된 필드의 타입은 변경 X.
- 다섯 갈래 = Static · Dynamic · Dynamic Templates · Multi-field · Runtime Field.
- Static Mapping = 명시적 정의, 운영 표준.
properties아래 type + options 박기. - 자주 쓰는 타입 = keyword · text · long · double · boolean · date · geo_point · ip · dense_vector · nested · object · flattened.
- text vs keyword = text 는 풀텍스트 검색 자리, keyword 는 정확 일치·정렬·집계 자리.
- Dynamic Mapping 모드 =
true(자동, 위험) ·false(무시) ·strict(거부, 권장). - Mapping Explosion = 임의 키 JSON + dynamic true → 필드 수 폭증 → 클러스터 메모리 터짐.
- 방벽 =
dynamic: strict+index.mapping.total_fields.limit: 1000. - Dynamic Templates =
match_mapping_type · match · unmatch로 자동 매핑에 규칙. 로그 인덱스 표준. - Multi-field =
fields키로 한 필드 → 여러 분석 방식 동시 색인. text + keyword 가 가장 흔한 패턴. - Runtime Field = 쿼리 시점 계산, reindex 없이 파생 필드. 느림 + 5개 이내 가이드.
- 변경 가능 = 필드 추가 · 서브 필드 추가 · runtime field. 변경 불가 = 기존 필드 타입 · analyzer · 필드 삭제.
- reindex 흐름 = 새 인덱스 →
_reindexAPI → alias 갈아끼기 → 옛 인덱스 삭제. - 운영 5계명 = strict 기본 · dynamic templates 로만 동적 자리 · multi-field 의미 자리만 · alias-first · runtime field 는 임시.
시리즈 다른 편
- 이전 글 = 7편 Document CRUD — Index·Get·Update·Delete·Bulk API
- 다음 글 = 9편 Field Types — text·keyword·numeric·date·geo·dense_vector 갈래
- 5편 = Index 관리 — Create·Settings·Alias·Reindex
- 10편 = Analyzer — Tokenizer·Filter·Custom Analyzer
- 11편 = Korean Analyzer — Nori·mecab-ko·사용자 사전
- 22편 = Vector Search — dense_vector·kNN·RAG
- 32편 = Spring Data Elasticsearch — @Document·@Field·Repository
- 38편 = 시리즈 마무리 — 결정 트리·체크리스트·자격증
한 줄 정리 — Mapping = ES 의 스키마 자리, 한 번 잡으면 변경 까다로움. Static + strict + Multi-field 셋이 운영 표준이고, Dynamic Templates 로만 동적 자리를 허용하고, Runtime Field 는 임시 자리로 쓴다. Mapping Explosion · text vs keyword · multi-field 누락 셋이 사고 단골.