우리가 쿠팡이나 쇼핑몰에서 검색을 통해 원하는 물건을 찾는다
이때 우리는 문자 순서에 상관없이 비슷한 물건을 조회할 수 있다
- ex) "맥북 에어 13" / "맥북 13 에어"
어떻게 이 검색이 가능할까? ElasticSearch 에서는 역인덱스를 통해 관련된 것을 찾아서 조회하게 된다
참고로 이런 작동 구조는 데이터 타입이 text 타입에 한해서만 적용된다
역인덱스 (Inverted Index)
- 필드 값을 단어마다 쪼개서 찾기 쉽게 정리해놓은 목록
- 예시를 통해서 알아보자
POST /products/_create/1
{
"name": "Apple 2025 맥북 에어 13 M4 10코어"
}
POST /products/_create/2
{
"name": "Apple 2024 에어팟 4세대"
}
POST /products/_create/3
{
"name": "Apple 2024 아이패드 mini A17 Pro"
}
위와 같이 데이터를 저장한다고 하자
특정 기준을 통해 단어를 추출
"name": "Apple 2025 맥북 에어 13 M4 10코어"
→ [Apple, 2025, 맥북, 에어, 13, M4, 10코어]
"name": "Apple 2024 에어팟 4세대"
→ [Apple, 2024, 에어팟, 4세대]
"name": "Apple 2024 아이패드 mini A17 Pro"
→ [Apple, 2024, 아이패드, mini, A17, Pro]
이후 역인덱스로 저장
| 토큰(token) | 도큐먼트 id |
|---|---|
| Apple | [1, 2, 3] |
| 2025 | [1] |
| 맥북 | [1] |
| 에어 | [1] |
| 13 | [1] |
| M4 | [1] |
| 10코어 | [1] |
| 2024 | [2, 3] |
| 에어팟 | [2] |
| 4세대 | [2] |
| 아이패드 | [3] |
| mini | [3] |
| A17 | [3] |
| Pro | [3] |
- 필드값에서 추출되어 역인덱스에 저장된 단어를 보고 토큰(token) 이라고 부른다
- 각 토큰에 대해 어디에 토큰이 포함되어 있는지를 도큐먼트 ID 로 저장
- "Apple" 의 경우 1, 2, 3 도큐먼트 모두 등장
- 생성된 역인덱스를 직접 눈으로 확인할 수는 없다, 시스템 내부적으로 생성될 뿐 이다
검색을 하면 역인덱스를 활용
만약 "Apple 2024 아이패드" 라고 검색한다면 역인덱스를 활용해 일치하는 단어가 많은 도큐먼트를 우선적으로 조회한다
| 토큰(token) | 도큐먼트 id |
|---|---|
| Apple | [1, 2, 3] |
| 2025 | [1] |
| 맥북 | [1] |
| 에어 | [1] |
| 13 | [1] |
| M4 | [1] |
| 10코어 | [1] |
| 2024 | [2, 3] |
| 에어팟 | [2] |
| 4세대 | [2] |
| 아이패드 | [3] |
| mini | [3] |
| A17 | [3] |
| Pro | [3] |
- 각 토큰이 어디 도큐먼트와 많이 일치하는지 역인덱스를 통해서 찾는다
- 종합적으로 ID 가 3인 도큐먼트가 가장 많이 일치하기 때문에 맨 처음으로 조회된다
- ID 가 1인 도큐먼트는 단어 1개 일치 → "Apple"
- ID 가 2인 도큐먼트는 단어 2개 일치 → "Apple", "2024"
- ID 가 3인 도큐먼트는 단어 3개 일치 → "Apple", "2024", "아이패드"
이와 같은 ES 의 자체적인 로직으로 score(점수)를 매겨 score 가 높은 순으로 도큐먼트를 조회한다
일반적으로 검색어와 관련성이 높으면 높을수록 score가 높게 측정된다

대략적인 score 계산
- Term Frequency (TF)
- 문서 내에서 검색어가 얼마나 자주 등장하는가
- 많이 등장할수록 점수가 높음
- Inverse Document Frequency (IDF)
- 검색어가 전체 문서 중 얼마나 희귀하냐
- 희귀할수록 점수가 높음 / 흔한 단어일수록 점수가 낮음
- Field Length Normalization
- 문서(필드)가 짧을수록 점수가 높다
- 검색어가 짧은 문서에서 등장하면 더 관련성이 높다고 판단
애널라이저(Analyzer)
- 필드값을 저장할 때 토큰으로 분리후 역인덱스로 저장하는 것을 살펴보았다
- 이 과정에서 문자열(text)을 토큰으로 변환시켜주는 장치를 보고 애널라이저라고 부른다

- 문자열을 간단하게 단어 단위로만 자르는 게 아니라 "애널라이저"가 여러가지의 작업을 거쳐서 토큰을 만들어낸다
- 내부적으로 "캐릭터 필터(character filter)", "토크나이저(tokenizer)", "토큰 필터(token filter)" 라는 걸 활용해 문자열을 토큰으로 변형시킨다
캐릭터 필터(character filter)
- 문자열을 토큰으로 자르기 전에 문자열을 다듬는 역할을 한다
- 다양한 종류의 필터가 존재, 여러 개의 필터를 적용시킬 수 있다
- ex)
- html_strip 필터 적용 (HTML 태그 제거) / "<h1>아이폰 15</h1>" → "아이폰 15"
- 그외에도 mapping 필터, pattern replace 필터 등이 존재
토크나이저(tokenizer)
- 문자열을 토큰으로 자르는 역할
- ex)
- standard 토크나이저 (공백 또는
,/./!/?와 같은 문장 부호를 기준으로 자름)- 그외에도 classic 토크나이저, keyword 토크나이저, pattern 토크나이저 등등
- standard 토크나이저 (공백 또는
토큰 필터(token filter)
- 잘린 토큰을 최종적으로 다듬는 역할
- ex)
- lowercase 필터 적용 (소문자로 변환)
- stop 필터 적용 (
a/the/is와 같은 특별한 의미를 가지 않는 단어 제거) - stemmer 필터 적용 (단어의 원래 형태로 변환)
- foxes → fox / jumped → jump
- 사실 위의 역직렬화 예시 표는 잘못된 예시이다. 기본적인 애널라이저를 사용한다면 standard analyzer 를 사용하게 되며 `lowercase` 라는 character filter 가 있기 때문에 소문자로 변환해서 토큰을 저장한다
- 아래는 실제 analyzer 분석

- 하지만 "apple" 로 저장되어도 "Apple" 도 검색이 된다 이유가 뭘까?
- 도큐먼트를 생성할 때 Analyzer 가 문자열을 토큰으로 분리해 역인덱스를 생성한다. 그런데 검색을 할 때도 Analyzer 가 검색어로 입력한 문자열을 토큰으로 분리해 검색한다

- 위와 같이 도큐먼트 생성과 검색은 같은 애널라이저 과정을 거치게 된다
한글과 영어를 섞은 단어 Analyzer
- 한글을 의미있게 토큰으로 만드는 Plugin 인 Nori Aanlyzer 를 붙인 후 테스트 해본 결과 한글에 알맞게 잘 적용된다는 것을 알게되었다
- 그러나 한글과 영어를 섞은 단어를 알맞게 역인덱스 저장하는 방식은 어떻게 해야할까?
GET /_analyze
{
"text": "오늘 영어 책에서 'It depends on the results.'이라는 문구를 봤다.",
"char_filter": [],
"tokenizer": "nori_tokenizer",
"filter": ["nori_part_of_speech", "nori_readingform", "lowercase", "stop", "stemmer"]
}nori_tokenizer를 통해서 한글을 알맞게 토크나이저 처리했다- 기본은
standard
- 기본은
- 이후
lowercase로 소문자 처리 stop을 통해 의미없는 영어 제거 (a,the등)stemmer를 통해 depends 라는 영단어를 → depend 로 원본 영단어로 변경
'학습일지 > ElasticSearch' 카테고리의 다른 글
| [ElasticSearch] ES 맛보기 - 자동검색 + 검색 기능 (0) | 2025.09.28 |
|---|