들어가며
검색 엔진에서 “삼성전자”를 검색했는데 결과가 안 나온다면? 대부분 Analyzer 설정 문제입니다. Analyzer가 텍스트를 어떻게 쪼개는지 이해하면 검색 품질을 크게 개선할 수 있습니다.
Analyzer란?
Analyzer는 텍스트를 검색 가능한 토큰으로 변환하는 파이프라인입니다.
3가지 구성 요소
| 구성 요소 | 역할 | 예시 |
|---|---|---|
| Character Filter | 문자 단위 전처리 | HTML 태그 제거, 특수문자 치환 |
| Tokenizer | 텍스트를 토큰으로 분리 | 공백 기준, 형태소 분석 |
| Token Filter | 토큰 후처리 | 소문자 변환, 불용어 제거, 동의어 처리 |
_analyze API로 토큰화 확인하기
가장 중요한 디버깅 도구입니다. 실제로 텍스트가 어떻게 분석되는지 확인할 수 있습니다.
Standard Analyzer (기본)
GET _analyze
{
"analyzer": "standard",
"text": "삼성전자 주가 10% 상승"
}결과:
{
"tokens": [
{ "token": "삼성전자", "position": 0 },
{ "token": "주가", "position": 1 },
{ "token": "10", "position": 2 },
{ "token": "상승", "position": 3 }
]
}Standard Analyzer는 공백과 특수문자 기준으로만 분리합니다. “삼성전자”가 하나의 토큰으로 남아있죠.
Nori Analyzer (한글 형태소 분석)
GET _analyze
{
"analyzer": "nori",
"text": "삼성전자 주가 10% 상승"
}결과:
{
"tokens": [
{ "token": "삼성", "position": 0 },
{ "token": "전자", "position": 1 },
{ "token": "주가", "position": 2 },
{ "token": "10", "position": 3 },
{ "token": "상승", "position": 4 }
]
}Nori는 “삼성전자”를 “삼성” + “전자”로 분리합니다. 형태소 분석의 결과죠.
Standard vs Nori 비교
주식 종목명으로 비교해봅시다.
| 입력 | Standard | Nori |
|---|---|---|
| 삼성전자 | [삼성전자] | [삼성, 전자] |
| SK하이닉스 | [sk하이닉스] | [sk, 하이닉스] 또는 [sk, 하이, 닉스] |
| LG에너지솔루션 | [lg에너지솔루션] | [lg, 에너지, 솔루션] |
| 카카오뱅크 | [카카오뱅크] | [카카오, 뱅크] |
검색 시나리오
사용자가 “삼성”으로 검색했을 때:
Nori Tokenizer 옵션
AWS OpenSearch에서는 Nori가 기본 내장되어 있습니다.
decompound_mode
복합어를 어떻게 처리할지 결정합니다.
PUT /stocks
{
"settings": {
"analysis": {
"tokenizer": {
"nori_tokenizer_mixed": {
"type": "nori_tokenizer",
"decompound_mode": "mixed"
}
},
"analyzer": {
"nori_mixed": {
"type": "custom",
"tokenizer": "nori_tokenizer_mixed"
}
}
}
}
}| 모드 | 설명 | “삼성전자” 결과 |
|---|---|---|
none |
분해 안 함 | [삼성전자] |
discard |
원본 버리고 분해 | [삼성, 전자] |
mixed |
원본 + 분해 모두 | [삼성전자, 삼성, 전자] |
mixed 모드를 쓰면 “삼성전자”로 검색해도, “삼성”으로 검색해도 모두 매칭됩니다.
분석 결과 확인
GET /stocks/_analyze
{
"analyzer": "nori_mixed",
"text": "삼성전자"
}인덱스 매핑에 Analyzer 적용
PUT /stocks
{
"settings": {
"analysis": {
"analyzer": {
"korean": {
"type": "nori",
"decompound_mode": "mixed"
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "korean"
},
"ticker": {
"type": "keyword"
}
}
}
}name: 종목명, Nori로 형태소 분석ticker: 종목코드, keyword로 정확 매칭 (005930, AAPL)
실전 예시: 주식 종목 인덱싱
POST /stocks/_bulk
{ "index": {} }
{ "name": "삼성전자", "ticker": "005930" }
{ "index": {} }
{ "name": "SK하이닉스", "ticker": "000660" }
{ "index": {} }
{ "name": "LG에너지솔루션", "ticker": "373220" }
{ "index": {} }
{ "name": "카카오뱅크", "ticker": "323410" }검색:
GET /stocks/_search
{
"query": {
"match": {
"name": "삼성"
}
}
}결과: 삼성전자가 검색됨!
주의사항
인덱싱과 검색 시 같은 Analyzer 사용
인덱싱할 때와 검색할 때 다른 Analyzer를 쓰면 토큰이 달라져서 매칭이 안 됩니다.
{
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "nori", // 인덱싱 시
"search_analyzer": "nori" // 검색 시 (생략하면 analyzer와 동일)
}
}
}
}Analyzer 변경 시 재인덱싱 필요
매핑의 Analyzer를 변경하면 기존 데이터는 이전 Analyzer로 토큰화된 상태입니다. 새 Analyzer를 적용하려면 재인덱싱이 필요합니다.
→ 이전 글 무중단 인덱스 교체 전략 참고
정리
| 항목 | Standard | Nori |
|---|---|---|
| 한글 처리 | 공백 기준 분리 | 형태소 분석 |
| “삼성전자” | 1개 토큰 | 2개 토큰 (삼성, 전자) |
| 부분 검색 | 안 됨 | 됨 |
| 사용 케이스 | 영문, 코드 | 한글 텍스트 |
다음 글에서는 term, match, match_phrase 쿼리의 차이를 알아보겠습니다.