DB Study

1장. Elasticsearch 개요 — 검색 엔진이라는 다른 세계

"MySQL 비슷한데 검색이 빠른 것"이라는 오해에서 벗어나는 것이 첫걸음입니다. 인덱스 자료구조가 다르면, 시스템의 모든 것이 달라집니다.

기초 ⏱ 약 20분 🎬 애니메이션 3개 선수 지식: 없음
🧭
이 장에서 배우는 것

① Elasticsearch의 정체성 = 분산 Lucene + REST ② RDB의 LIKE 검색과 역색인 검색은 무엇이 다른가 ③ NRT(near real-time)가 "느린 것"이 아니라 "의도된 설계"인 이유 ④ Elastic Stack의 구성과 분산 시스템 핵심 원칙

1.1 Elasticsearch는 어떤 시스템인가

Elasticsearch는 Apache Lucene 기반의 분산 검색·분석 엔진(Distributed Search and Analytics Engine)입니다. 공식 문서의 정의를 풀어보면 네 가지 키워드가 나옵니다.

마지막 항목이 핵심입니다. 한 줄로 요약하면 이렇게 이해해도 큰 무리가 없습니다.

💡
한 줄 요약

Elasticsearch ≈ 분산 Lucene + REST API + 클러스터 관리. Lucene 인덱스를 여러 노드에 나눠 담고(샤딩), 복제하고, 요청을 라우팅해 주는 레이어가 Elasticsearch입니다. 그래서 3장에서 Lucene 내부를, 2·4장에서 분산 레이어를 다룹니다.

버전에 대한 기준도 정해둡시다. 이 가이드는 8.17 LTS를 baseline으로 하고, 9.x 고유 변경점은 박스로 따로 표기합니다. 9.x는 Lucene 10 기반(8.x는 Lucene 9)이며, SIMD 최적화·BBQ(Better Binary Quantization) GA 등 성능 향상 대부분이 Lucene 10에서 옵니다.

1.2 RDB의 LIKE 검색 vs 역색인 검색

RDBMS의 인덱스는 보통 B-Tree입니다. B-Tree는 WHERE name = 'Alice' 같은 정확한 값 매치에 최적화되어 있습니다. 하지만 "본문에 'fox'라는 단어가 포함된 모든 문서"를 찾으려면 어떻게 될까요? LIKE '%fox%'는 인덱스를 쓰지 못하고 모든 행을 처음부터 끝까지 읽는 풀스캔이 됩니다.

Elasticsearch(Lucene)는 역색인(Inverted Index)을 씁니다. "term → 그 term이 등장한 문서 목록(posting list)"을 미리 만들어 두는 것입니다. 책 뒤편의 '찾아보기' 페이지와 정확히 같은 원리입니다. 두 방식이 같은 검색을 처리하는 과정을 비교해 봅시다.

🐢 RDB — LIKE '%fox%' row 1: "the quick brown fox" row 2: "the lazy dog" row 3: "quick dog runs" row 4 ... row 10,000,000 row 1: "the quick brown fox" ← 스캔 row 2: "the lazy dog" row 3: "quick dog runs" row 4 ... row 10,000,000 ⛔ 천만 행 전부 문자열 스캔 B-Tree 인덱스는 '%..%' 패턴에 무력 ⚡ Elasticsearch — 역색인 term dictionary → posting list brown → doc1 dog → doc2, doc3 fox → doc1 quick → doc1, doc3 fox → doc1 ← 사전에서 바로 룩업! doc1 반환 ✨ 문서 수가 천만이어도 룩업은 ms 단위

역색인이라는 자료구조에서 Elasticsearch의 성격이 그대로 따라 나옵니다.

RDBMS (B-Tree)Elasticsearch (역색인)
잘하는 것정확 매치, 범위 검색, 트랜잭션, JOIN풀텍스트 검색, 집계, 대규모 분산
부분 문자열 검색LIKE '%..%' = 풀스캔토큰 룩업 = ms 단위
쓰기 방식제자리 갱신(in-place)불변 세그먼트 + 백그라운드 머지
검색 가시성커밋 즉시기본 1초 후 (NRT)
스키마DDL로 엄격매핑(mapping) — 유연하지만 함정 있음 (5장)

1.3 Near-Real-Time — "1초 늦는 것"은 버그가 아니다

Elasticsearch에 문서를 색인하고 곧바로 검색하면, 그 문서가 안 보일 수 있습니다. 처음 겪으면 당황하는 현상이지만, 이는 NRT(near real-time) 검색이라는 의도된 설계입니다. 새 문서는 기본 1초 간격의 refresh_interval이 지나야 검색에 노출됩니다.

t = 0s t ≈ 0.5s t = 1s (refresh) ① 색인 요청 POST /products/_doc 메모리 버퍼에 기록됨 (+ translog로 디스크 보존) ② 즉시 검색해 보면? GET /_search "새상품" ❌ 결과 0건 — 아직 세그먼트가 아님 ③ refresh 발생! 버퍼 → 검색 가능한 세그먼트 ✅ 이제 검색에 노출됨 💡 매 문서마다 fsync하지 않고 1초 단위로 묶어 처리 → 색인 처리량 극대화
⚠️
"방금 쓴 걸 바로 읽어야" 한다면

테스트 코드나 write-then-read 시나리오에서는 ?refresh=wait_for 옵션으로 refresh를 기다리게 할 수 있습니다. 단, 운영 트래픽에서 남용하면 색인 성능이 크게 떨어집니다. Elasticsearch의 검색 경로는 기본적으로 strong consistency를 보장하지 않는다는 점을 기억하세요.

직접 확인해 봅시다. Elasticsearch는 RESTful이므로 curl만 있으면 됩니다.

# 문서 색인 (인덱스가 없으면 자동 생성)
POST /products/_doc
{
  "name": "quick brown fox 인형",
  "price": 15000
}

# 풀텍스트 검색 — 1초 후에는 검색됨
GET /products/_search
{
  "query": { "match": { "name": "fox" } }
}

# 테스트용: refresh를 기다렸다가 응답 받기
POST /products/_doc?refresh=wait_for
{ "name": "바로 검색돼야 하는 문서" }

1.4 무엇에 쓰는 물건인가 — 4대 사용 사례

🔎 Full-Text Search

상품 검색, 문서 검색, 사이트 내 검색. BM25 스코어링, 한국어 형태소 분석(nori), 자동완성(suggest)이 주무기입니다.

📈 Observability (로그·메트릭·트레이스)

로그 분석의 사실상 표준. Beats/Elastic Agent로 수집해 시간 기반 인덱스(logs-app-2026.07.11)에 색인하고 Kibana로 시각화합니다.

🛡️ Security Analytics (SIEM)

보안 이벤트를 색인하고 룰 기반 탐지(EQL), 행위 분석, 위협 헌팅을 수행하는 Elastic Security의 백엔드입니다.

🧠 Vector Search (시맨틱 검색)

8.x부터 dense_vector + kNN 검색 지원. 9.x에서 BBQ가 GA되어 메모리 32배 절감 + 8~30배 처리량. RAG·추천에 활용됩니다.

1.5 Elastic Stack — 혼자 다니지 않는다

Elasticsearch는 보통 수집기·시각화 도구와 한 세트로 움직입니다. 데이터가 흐르는 경로를 봅시다.

🖥️ 애플리케이션 서버 app.log 생성 Elastic Agent / Beats 경량 수집기 (Shipper) Logstash (선택) 무거운 ETL: grok 파싱, enrichment, 다중 출력 🔍 Elasticsearch 저장 + 검색 + 집계 logs-app-2026.07.11 📊 Kibana — 시각화·관리 UI 대시보드, Dev Tools, 알림, Fleet(에이전트 중앙 관리)
컴포넌트역할
Elasticsearch데이터 저장, 검색, 집계. 모든 것의 중심
Kibana시각화, 대시보드, 클러스터 관리, Dev Tools
Logstash무거운 ETL — grok 파싱, enrichment, 다중 출력
Beats경량 수집기 (Filebeat, Metricbeat 등)
Elastic Agent + FleetBeats를 하나로 묶은 차세대 수집기 + 중앙 정책 관리. 신규 도입 표준

1.6 분산 시스템 핵심 원칙 — 미리보기

Elasticsearch가 Lucene 위에 얹는 분산 레이어의 핵심 개념 세 가지만 미리 잡아둡시다. 자세한 내용은 2장과 4장에서 다룹니다.

# 클러스터가 살아있는지, 샤드 상태는 어떤지 — 운영자의 첫 명령
GET /_cluster/health

{
  "cluster_name": "prod-search",
  "status": "green",          ← green/yellow/red
  "number_of_nodes": 6,
  "active_primary_shards": 120,
  "active_shards": 240          ← primary + replica
}
🚨
운영 원칙 미리보기 — 나중에 후회하지 않으려면

① primary 샤드 수는 생성 후 바꾸기 어렵습니다 (4장). ② 샤드가 너무 많으면 클러스터가 통째로 흔들립니다(oversharding). ③ 대량 색인은 반드시 bulk API로. ④ 운영 환경은 마스터 전용 노드 3대 분리(2장). ⑤ 업그레이드는 N → N+1 단위 — 8.x → 9.x는 8.19 경유 필수.

✍️ 이해도 체크

RDB의 LIKE '%fox%'가 느리고 Elasticsearch의 같은 검색이 빠른 근본적인 이유는?
✅ 핵심은 자료구조입니다. B-Tree는 '%..%' 패턴에서 인덱스를 쓰지 못해 풀스캔이 되지만, 역색인은 "term → 문서 목록"을 미리 만들어 두므로 검색이 정렬된 사전에서의 룩업 + posting list 조회로 끝납니다.
문서를 색인한 직후 검색했더니 결과에 나오지 않습니다. 가장 가능성 높은 이유는?
✅ Elasticsearch는 NRT(near real-time) 검색입니다. 새 문서는 refresh가 일어나 세그먼트가 되어야 검색에 노출됩니다(기본 1초). 데이터 자체는 translog에 안전하게 기록되어 있으므로 유실이 아닙니다. 즉시 확인이 필요하면 ?refresh=wait_for를 사용하세요.
📚
원문으로 더 깊이

이 장의 원문 문서: chapters/ch01_elasticsearch_overview.md — 9.x 변경점 전체 목록, eventual consistency의 상세 조건 등이 담겨 있습니다.