Elasticsearch 동적 매핑으로 인한 필드 타입 충돌 해결
문제 상황
재택근무 전환 이후 여러 서비스의 로그를 Elasticsearch로 통합하는 작업을 진행했다. Filebeat로 로그를 수집하다가 특정 인덱스에서 간헐적으로 인덱싱 실패가 발생했다.
에러 로그를 확인하니 user_id 필드의 타입 충돌이었다. 일부 서비스는 숫자형 ID를, 다른 서비스는 UUID 문자열을 사용하고 있었다.
{
"error": {
"type": "mapper_parsing_exception",
"reason": "failed to parse field [user_id] of type [long]"
}
}
동적 매핑의 함정
Elasticsearch는 첫 번째 문서를 기준으로 필드 타입을 자동 결정한다. 운이 나쁘게 숫자형 ID가 먼저 들어왔고, 이후 문자열 ID는 모두 거부당했다.
인덱스 매핑을 확인했다.
GET /app-logs-2020.05/_mapping
예상대로 user_id가 long 타입으로 고정되어 있었다.
해결 방법
1. 인덱스 템플릿 수정
새로운 인덱스부터는 명시적 매핑을 적용하도록 템플릿을 생성했다.
PUT _index_template/app-logs-template
{
"index_patterns": ["app-logs-*"],
"template": {
"mappings": {
"properties": {
"user_id": {
"type": "keyword"
}
}
}
}
}
2. 기존 데이터 Reindex
이미 생성된 인덱스는 Reindex API로 재색인했다.
POST _reindex
{
"source": {
"index": "app-logs-2020.05"
},
"dest": {
"index": "app-logs-2020.05-v2"
}
}
3. Ingest Pipeline 적용
추가적인 방어책으로 데이터 정규화 파이프라인을 구성했다.
PUT _ingest/pipeline/user-id-normalizer
{
"processors": [
{
"convert": {
"field": "user_id",
"type": "string",
"ignore_failure": true
}
}
]
}
교훈
동적 매핑은 프로토타이핑에는 편하지만, 프로덕션에서는 예상치 못한 타입 충돌을 일으킨다. 특히 여러 소스에서 데이터를 수집할 때는 반드시 명시적 매핑을 사용해야 한다. 인덱스 템플릿과 Ingest Pipeline을 활용하면 데이터 일관성을 미리 보장할 수 있다.