Elasticsearch 마스터 — Analyzer·Tokenizer·한국어 분석

2026-05-03확률과 통계 마스터 노트

Elasticsearch 마스터 노트 시리즈 3편. Analyzer가 text 필드를 토큰화하는 3단계(char filter·tokenizer·token filter), Standard Analyzer 동작, 한국어 분석기 Nori의 형태소 분석, Custom Analyzer 구성, N-Gram 분석으로 부분 검색, _analyze API로 결과 확인까지.

이 글은 Elasticsearch 마스터 노트 시리즈의 세 번째 편입니다. 2편(Mapping)에서 text vs keyword를 봤다면, 이번엔 text가 어떻게 처리되나 — Analyzer.

"Spring Boot Framework" 가 어떻게 ["spring", "boot", "framework"]로 변환? 이 변환이 검색 결과를 결정. 한국어 환경 = Nori 분석기.

처음 Analyzer가 어렵게 느껴지는 이유

처음 이 단원이 어렵게 느껴지는 이유는 두 가지예요. 첫째, **3 단계 (char filter·tokenizer·token filter)**가 막연합니다. 둘째, 한국어는 영어와 달라 표준 분석기가 안 맞습니다.

해결법은 한 가지예요. "text → 토큰 리스트로 변환". 분석기 = 텍스트 → 검색 가능한 단어들. 한국어 = 형태소 분석 (Nori).

Analyzer 3 단계

[Original Text]
    ↓
[Character Filter] (특수문자 처리·HTML 제거)
    ↓
[Tokenizer] (단어 분리)
    ↓
[Token Filter] (소문자·stopword·stemming)
    ↓
[Tokens]

각 단계 독립적·구성 가능.

Standard Analyzer — 기본

"Spring Boot 2024!"
    ↓ Tokenizer (공백·구두점 분리)
["Spring", "Boot", "2024"]
    ↓ Lowercase Token Filter
["spring", "boot", "2024"]

여기서 시험 함정이 하나 있어요. Standard Analyzer는 영어 친화. 한국어는 공백만으로 분리 → "검색엔진" 같은 명사 분리 X.

_analyze API — 결과 확인

GET /_analyze
{
  "analyzer": "standard",
  "text": "Spring Boot Framework"
}

# 결과
{
  "tokens": [
    { "token": "spring", "position": 0 },
    { "token": "boot", "position": 1 },
    { "token": "framework", "position": 2 }
  ]
}

검색 시 어떻게 토큰화되는지 미리 확인. 디버깅 핵심.

빌트인 Analyzer

분석기 동작
Standard 기본 (공백·구두점·소문자)
Simple 알파벳 외 분리·소문자 (숫자 제거)
Whitespace 공백만 분리 (소문자 X)
Keyword 분리 X (전체 1 토큰)
Stop Standard + 불용어 제거
Pattern 정규식 기반
English 영어 stemming·불용어
Language French·German 등 다국어

English Analyzer

GET /_analyze
{
  "analyzer": "english",
  "text": "running runs ran"
}

# 결과 — stemming
[
  { "token": "run" },
  { "token": "run" },
  { "token": "ran" }
]

running·runsrun (어간 추출).

한국어 — Nori Analyzer

설치

# 플러그인 설치 (Elasticsearch)
bin/elasticsearch-plugin install analysis-nori

또는 Docker:

elasticsearch:
  image: elasticsearch:8.x
  environment:
    - "ES_PLUGINS=analysis-nori"

사용

GET /_analyze
{
  "analyzer": "nori",
  "text": "Spring Boot로 만드는 검색엔진"
}

# 결과 — 형태소 분석
[
  { "token": "spring" },
  { "token": "boot" },
  { "token": "만들" },
  { "token": "검색" },
  { "token": "엔진" }
]

여기서 정말 중요한 시험 함정 — 한국어 = Nori 필수. Standard Analyzer는 한국어 형태소 X. "검색엔진"이 분리 안 되어 "검색"만으로 검색 시 X.

Nori 옵션

PUT /products
{
  "settings": {
    "analysis": {
      "analyzer": {
        "korean_analyzer": {
          "type": "nori",
          "decompound_mode": "mixed",
          "user_dictionary": "user_dict.txt"
        }
      }
    }
  }
}
Decompound Mode 의미
none 복합어 분해 X ("검색엔진" 그대로)
discard 분해된 토큰만 ("검색", "엔진")
mixed 원본 + 분해 ("검색엔진", "검색", "엔진")

여기서 시험 함정이 하나 있어요. mixed가 일반 권장. 사용자가 "검색엔진"으로도 "검색"으로도 찾을 수 있음.

사용자 정의 사전

# user_dict.txt
스프링부트
검색엔진,검색,엔진

특정 명사 명시. 도메인 용어·신조어에 유용.

Custom Analyzer

PUT /my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_analyzer": {
          "type": "custom",
          "char_filter": ["html_strip"],
          "tokenizer": "standard",
          "filter": ["lowercase", "stop", "snowball"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "analyzer": "my_custom_analyzer"
      }
    }
  }
}

3 단계 자유 조합.

Character Filter

필터 동작
html_strip HTML 태그 제거
mapping 문자 매핑 (& → and)
pattern_replace 정규식 치환
GET /_analyze
{
  "char_filter": ["html_strip"],
  "tokenizer": "standard",
  "text": "<p>Hello <b>World</b></p>"
}
# → "Hello World"

Tokenizer 종류

Tokenizer 동작
standard 단어 + 공백 + 구두점
whitespace 공백만
keyword 분리 X
pattern 정규식
ngram N-gram
edge_ngram Edge N-gram
path_hierarchy 경로 계층
nori_tokenizer 한국어 형태소

Token Filter

lowercase    — 소문자
uppercase    — 대문자
stop         — 불용어 제거
stemmer      — 어간 추출 (영어)
synonym      — 동의어
unique       — 중복 제거
asciifolding — 악센트 제거 (é → e)

Stop (불용어)

PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "english_stop": {
          "type": "stop",
          "stopwords": ["the", "a", "an", "and", "or"]
        }
      },
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "standard",
          "filter": ["lowercase", "english_stop"]
        }
      }
    }
  }
}

Synonym (동의어)

"filter": {
  "my_synonym": {
    "type": "synonym",
    "synonyms": [
      "스마트폰, 휴대폰, 핸드폰",
      "노트북 => 랩탑"
    ]
  }
}

스마트폰·휴대폰·핸드폰 모두 같은 토큰으로. 노트북랩탑만 (단방향).

N-Gram — 부분 검색

PUT /my_index
{
  "settings": {
    "analysis": {
      "tokenizer": {
        "my_ngram": {
          "type": "ngram",
          "min_gram": 2,
          "max_gram": 3
        }
      },
      "analyzer": {
        "ngram_analyzer": {
          "tokenizer": "my_ngram"
        }
      }
    }
  }
}

GET /my_index/_analyze
{
  "analyzer": "ngram_analyzer",
  "text": "spring"
}
# → ["sp", "spr", "pr", "pri", "ri", "rin", "in", "ing", "ng"]

여기서 시험 함정이 하나 있어요. N-Gram = 부분 매칭 가능. "spri"로도 "spring" 찾기. 다만 인덱스 크기 폭증·검색 속도 ↓. 자동완성·작은 필드에만.

Edge N-Gram — 자동완성

PUT /my_index
{
  "settings": {
    "analysis": {
      "tokenizer": {
        "edge_ngram": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 10
        }
      }
    }
  }
}

GET /my_index/_analyze
{
  "tokenizer": "edge_ngram",
  "text": "spring"
}
# → ["sp", "spr", "spri", "sprin", "spring"]

앞에서부터만. 자동완성에 표준.

search_analyzer — 검색 시 다른 분석기

"name": {
  "type": "text",
  "analyzer": "edge_ngram_analyzer",      # 인덱싱 시
  "search_analyzer": "standard"            # 검색 시
}

저장 = N-Gram 다양하게, 검색 = 표준 (사용자 입력 그대로).

여기서 정말 중요한 시험 함정 — 인덱싱 분석 vs 검색 분석 분리. 자동완성·N-Gram에 표준. 안 분리하면 검색어도 N-Gram 분해 → 의도 다른 결과.

운영 권장 패턴

한국어 + 영어 혼합:
  - nori_tokenizer (한국어 형태소)
  - lowercase
  - stop (한국어·영어 불용어)
  - synonym (도메인 동의어)
  
자동완성:
  - edge_ngram (인덱싱)
  - standard (검색)
  
정확 매칭:
  - keyword 타입 (분석 X)

시험 직전 한 번 더 — 자주 헷갈리는 함정 모음

여기까지가 3편의 핵심입니다. 시험 직전 또는 실무에서 헷갈릴 때 다시 펼쳐 볼 수 있게 압축 노트로 마무리할게요.

  • Analyzer 3 단계 — Char Filter / Tokenizer / Token Filter
  • _analyze API로 결과 확인 (디버깅 핵심)
  • 빌트인 — Standard·Simple·Whitespace·Keyword·Stop·English·Language
  • Standard = 영어 친화 (한국어 X)
  • 한국어 = Nori 필수
  • 플러그인 — analysis-nori
  • Decompound Mode — none·discard·mixed (권장)
  • mixed = 원본 + 분해 (검색엔진·검색·엔진)
  • 사용자 정의 사전user_dictionary (도메인 용어·신조어)
  • Custom Analyzer = 3 단계 자유 조합
  • Char Filter — html_strip·mapping·pattern_replace
  • Tokenizer — standard·ngram·edge_ngram·nori_tokenizer
  • Token Filter — lowercase·stop·stemmer·synonym·asciifolding
  • Synonym — 양방향 (,) / 단방향 (=>)
  • N-Gram = 부분 검색 (인덱스 폭증·자동완성에)
  • Edge N-Gram = 자동완성 표준 (앞에서만)
  • search_analyzer = 검색 시 다른 분석기
  • 자동완성 = edge_ngram(인덱싱) + standard(검색)
  • 한국어 + 영어 혼합 = nori + lowercase + stop + synonym

시리즈 다른 편

공식 문서: Analysis / Nori Plugin 에서 더 깊이.

다음 글(4편)에서는 Query DSL — JSON 기반 검색 쿼리, term/match/bool/range 등 핵심 쿼리, filter context까지 풀어 갑니다.

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!