검색은 어떻게 이렇게 빠를까?

2026년 07월 23일

opensearch

시리즈OpenSearch 내부 구조#2
# OpenSearch# 역색인# 형태소분석# Nori# Lucene
목차

들어가며

상품이 100만 건 있습니다. 여기서 “노트북”을 검색하면 결과가 즉시 나옵니다.

그런데 이상하지 않나요? 100만 건을 다 뒤졌다면 그렇게 빠를 리가 없는데요.

답은 미리 뒤져놨기 때문입니다. 검색할 때 뒤지는 게 아니라, 문서를 넣을 때 이미 다 정리해둡니다. 그 정리된 결과물이 세그먼트 안에 들어있는 역색인(inverted index) 이에요.

ℹ️

이번 글의 범위

  • 다루는 것: 역색인 구조, 왜 빠른지, 형태소 분석이 필요한 이유(맛보기)
  • 다루지 않는 것: 형태소 분석 상세(2차 시리즈), 관련도 점수 계산(2차 시리즈)

책 뒤의 “찾아보기”

두꺼운 기술서적 맨 뒤를 보면 이런 게 있습니다.

찾아보기

가비지 컬렉션 ......... 45, 120, 121
데드락 ................ 87
트랜잭션 .............. 12, 34, 56, 91

“트랜잭션”이 몇 페이지에 나오는지 알고 싶을 때, 1페이지부터 넘기며 찾지 않죠. 찾아보기에서 “트랜잭션”을 보면 바로 12, 34, 56, 91 이 나옵니다.

역색인이 정확히 이겁니다. 이름이 “역(inverted)“인 이유는 방향을 뒤집었기 때문이에요.

방향형태예
정방향문서 → 단어12페이지에는 [트랜잭션, 락, 격리수준] 이 있다
역방향단어 → 문서“트랜잭션”은 [12, 34, 56, 91] 페이지에 있다

우리가 검색할 때 원하는 건 항상 역방향입니다. 그래서 미리 뒤집어서 저장해두는 거예요.


실제로 어떻게 생겼나

문서 3개를 색인한다고 해봅시다.

문서 1: "무선 노트북 마우스"
문서 2: "노트북 거치대"
문서 3: "무선 키보드"

먼저 각 문서를 단어로 쪼갭니다 (정방향).

1 → [무선, 노트북, 마우스]
2 → [노트북, 거치대]
3 → [무선, 키보드]

이걸 뒤집으면 역색인이 됩니다.

단어 (term)문서 목록 (posting list)
거치대2
노트북1, 2
마우스1
무선1, 3
키보드3

이제 “노트북”을 검색하면 표에서 한 줄만 보면 됩니다. 문서를 하나도 열어보지 않고 1, 2가 나와요.

검색: 노트북역색인에서'노트북' 한 줄 조회문서 1, 2

💡

표가 사전순으로 정렬된 걸 눈여겨보세요.

거치대 → 노트북 → 마우스 → 무선 → 키보드. 가나다순입니다.

정렬돼 있으면 이진 탐색이 가능합니다. 단어가 100만 개여도 스무 번 정도만 비교하면 원하는 단어에 도달해요. 이게 “미리 정리해둔다”의 실체입니다.


여기서 불변성의 씨앗이 나온다

정렬돼 있어서 빠르다는 건, 뒤집어 말하면 정렬을 유지해야 한다는 뜻입니다.

새 문서에 “노트북받침”이라는 단어가 나왔다고 해봅시다. 이 단어는 사전순으로 “노트북”과 “마우스” 사이에 들어가야 합니다.

거치대
노트북
노트북받침   ← 여기에 끼워넣어야 함
마우스
무선
키보드

파일 중간에 끼워넣으려면 뒤에 있는 내용을 전부 밀어야 합니다. 단어가 100만 개라면 재앙이죠.

그래서 Lucene은 아예 다른 선택을 합니다.

기존 파일은 건드리지 않는다. 새 파일을 하나 더 만든다.

이게 1편에서 말한 “세그먼트는 인쇄된 책”의 진짜 이유입니다. 고치는 게 너무 비싸서, 고치지 않기로 한 거예요. 검색할 때는 책 여러 권을 동시에 뒤지고 결과를 합칩니다.

⚠️

그럼 세그먼트가 계속 늘어나지 않나요?

맞습니다. 그래서 주기적으로 여러 권을 한 권으로 합치는 작업이 있습니다. 이걸 merge라고 하고, 3편에서 직접 눌러보게 됩니다.


단어는 누가 쪼개나

역색인을 만들려면 먼저 문장을 단어로 쪼개야 합니다. 이 일을 하는 게 분석기(Analyzer) 이고, 쪼개진 결과물을 토큰(token) 이라고 부릅니다.

영어는 쉽습니다. 공백으로 자르면 대충 맞아요.

"wireless laptop mouse" → [wireless, laptop, mouse]

한글은 그렇지 않습니다. 여기서 대부분의 검색 사고가 터집니다.

문제 ① 조사가 달라붙는다

한국어는 명사 뒤에 조사가 붙습니다.

"학교에서 만났다"   → 공백 분리 → [학교에서, 만났다]
"학교를 다닌다"     → 공백 분리 → [학교를, 다닌다]
"학교가 크다"       → 공백 분리 → [학교가, 크다]

전부 다른 토큰이 됩니다. 그래서 사용자가 “학교” 로 검색하면?

역색인:  학교에서 → [1]
         학교를   → [2]
         학교가   → [3]

검색어:  학교     → 일치하는 단어 없음 → 결과 0건 💥

세 문서 모두 학교 이야기인데 하나도 안 나옵니다.

형태소 분석기를 쓰면 이렇게 됩니다.

"학교에서 만났다" → [학교, 에서, 만나, 았다]
                     ↑ 조사가 분리됨

역색인:  학교 → [1, 2, 3]
검색어:  학교 → 3건 모두 매칭 ✅

문제 ② 어미가 변한다

동사와 형용사는 형태가 계속 바뀝니다.

먹었다 / 먹는다 / 먹고 / 먹어서   → 전부 다른 토큰
예쁜  / 예뻤다 / 예쁘고          → 전부 다른 토큰

“먹다”로 검색해도 아무것도 안 걸립니다. 형태소 분석기는 여기서 어간(변하지 않는 부분) 을 뽑아냅니다.

먹었다 → [먹, 었다]
먹는다 → [먹, 는다]
먹고   → [먹, 고]
        ↑ 공통 어간
ℹ️

형태소(morpheme)란?

뜻을 가진 가장 작은 단위입니다. “학교에서”는 학교(뜻이 있음) + 에서(문법적 역할)로 나뉘고, 더 쪼개면 뜻이 사라집니다. 한국어처럼 조사와 어미가 계속 붙는 언어를 교착어라고 하는데, 교착어는 형태소 단위로 쪼개지 않으면 검색이 성립하지 않습니다.

한국어 형태소 분석에는 보통 Nori라는 분석기를 씁니다. AWS OpenSearch에는 기본 내장되어 있어요.

GET _analyze
{
  "analyzer": "nori",
  "text": "학교에서 만났다"
}
💡

형태소 분석은 그 자체로 깊은 주제입니다.

사용자 사전(신조어·브랜드명), 품사 필터(조사·어미 버리기), 동의어 처리, 복합명사를 어디까지 쪼갤 것인가 등 실전에서 다룰 게 많습니다. 이건 2차 시리즈 「검색 A-Z」 에서 예시와 함께 본격적으로 다룹니다.

이 글에서는 “역색인을 만들려면 먼저 단어로 쪼개야 하고, 한글은 그게 어렵다”는 것만 기억하면 충분합니다.


색인과 검색은 같은 분석기를 써야 한다

여기서 반드시 짚고 갈 함정이 하나 있습니다.

문서를 넣을 때와 검색할 때 다른 분석기를 쓰면, 토큰이 달라져서 매칭이 안 됩니다.

검색할 때색인할 때분석기 A분석기 B토큰 불일치 → 0건삼성전자[삼성전자]삼성전자[삼성, 전자]

같은 글자를 넣었는데 결과가 안 나오는 황당한 상황이 여기서 생깁니다. 그래서 매핑에서 analyzer만 지정하면 검색에도 같은 게 자동 적용되고, 굳이 다르게 하고 싶을 때만 search_analyzer를 따로 줍니다.


정리

  1. 역색인은 “단어 → 문서” 방향으로 미리 뒤집어둔 표다. 책 뒤 찾아보기와 같다. 그래서 문서를 열지 않고도 답이 나온다.
  2. 역색인은 사전순으로 정렬돼 있다. 그래서 빠르고, 그래서 중간 삽입이 비싸다.
  3. 비싸서 안 고치기로 한 결과가 세그먼트 불변성이다. 고치는 대신 새 세그먼트를 만든다.
  4. 역색인을 만들려면 문장을 단어로 쪼개야 하고, 한글은 형태소 분석 없이는 검색이 성립하지 않는다.

다음 글에서는 문서를 하나 넣었을 때 세그먼트가 만들어지기까지 무슨 일이 벌어지는지 직접 눌러보며 확인합니다.

🤔역색인이 검색을 빠르게 만드는 핵심 이유는?

참고자료

© 2026, 미나리와 함께 만들었음