본문으로 건너뛰기
Elasticsearch 검색 엔진 입문 가이드
검색 엔진 / · PT5M read

Elasticsearch 입문: 검색 엔진이 필요한 이유

프로덕션에서 터진 검색 장애

금요일 오후 5시, 퇴근 직전에 슬랙 알림이 울렸다.

🚨 [ALERT] Database CPU 95% - Product Search API
Response Time: 12,000ms (threshold: 500ms)
Error Rate: 45%

이커머스 서비스의 상품 검색이 완전히 멈춰버렸다. 원인은 단순했다. 블랙 프라이데이 프로모션으로 트래픽이 3배 증가했는데, 상품 검색이 MySQL의 LIKE '%keyword%' 쿼리로 동작하고 있었던 것이다.

-- 문제의 쿼리
SELECT * FROM products
WHERE name LIKE '%블루투스 이어폰%'
   OR description LIKE '%블루투스 이어폰%'
ORDER BY created_at DESC
LIMIT 20;

200만 개의 상품 데이터에서 이 쿼리는 Full Table Scan을 수행했고, 동시 접속자 수가 늘어나자 데이터베이스가 버티지 못했다.

이 글에서는 왜 RDBMS의 LIKE 검색이 프로덕션에서 문제가 되는지, 전문 검색 엔진이 이를 어떻게 해결하는지, 그리고 Elasticsearch의 핵심 개념을 알아본다.

RDBMS LIKE 검색의 한계

왜 LIKE ‘%keyword%‘는 느린가?

일반적인 B-Tree 인덱스는 왼쪽부터 시작하는 검색에만 효과적이다.

-- 인덱스 사용 가능 (Left-anchored)
SELECT * FROM products WHERE name LIKE '블루투스%';

-- 인덱스 사용 불가 (Full Table Scan)
SELECT * FROM products WHERE name LIKE '%블루투스%';

%가 앞에 붙는 순간, 데이터베이스는 모든 행을 하나씩 확인해야 한다. 100만 행이면 100만 번의 문자열 비교가 발생한다.

실제 성능 비교

MySQL 8.0에서 100만 개 상품 데이터로 테스트한 결과:

쿼리 패턴실행 시간인덱스 사용
LIKE 'keyword%'15ms✅ B-Tree Index
LIKE '%keyword%'2,800ms❌ Full Table Scan
LIKE '%key%word%'3,200ms❌ Full Table Scan

동시 요청이 100개만 되어도 데이터베이스 커넥션 풀이 고갈된다.

Full-Text Index의 한계

MySQL과 PostgreSQL은 Full-Text Index를 지원하지만 한계가 있다:

-- MySQL Full-Text Search
ALTER TABLE products ADD FULLTEXT INDEX ft_idx (name, description);

SELECT * FROM products
WHERE MATCH(name, description) AGAINST('블루투스 이어폰' IN NATURAL LANGUAGE MODE);

문제점:

  • 한국어 지원 미흡: 기본 파서가 공백 기준으로만 토큰화
  • 실시간 업데이트 부담: 대량 INSERT/UPDATE 시 인덱스 재구축 오버헤드
  • 고급 기능 부재: 형태소 분석, 동의어 처리, 자동완성 등 미지원
  • 분산 확장 불가: 단일 서버의 물리적 한계

검색 엔진이 필요한 순간

다음 요구사항 중 하나라도 해당되면 전문 검색 엔진을 고려해야 한다:

  1. 대량 텍스트 검색: 수십만 건 이상의 텍스트 데이터에서 키워드 검색
  2. 한국어 검색: 형태소 분석이 필요한 언어
  3. 자동완성: 입력 중 실시간 검색어 제안
  4. 오타 허용: “블루투쓰” → “블루투스” 매칭
  5. 관련성 랭킹: 단순 일치가 아닌 관련도 순 정렬
  6. 확장성: 데이터 증가에 따른 수평 확장 필요

역인덱스(Inverted Index)란?

Elasticsearch의 핵심은 역인덱스다. 일반적인 인덱스가 “문서 → 단어”를 매핑한다면, 역인덱스는 “단어 → 문서”를 매핑한다.

책의 색인과 같은 원리

책 뒤에 있는 색인(Index)을 생각해보자:

책의 색인:
- Elasticsearch ... 12, 45, 89, 102
- 검색 ............ 15, 23, 67, 89
- 인덱스 .......... 45, 78, 102

“Elasticsearch”를 찾고 싶으면 색인에서 해당 단어를 찾고, 페이지 번호(12, 45, 89, 102)로 바로 이동한다. 책 전체를 읽을 필요가 없다.

역인덱스 구조

다음 세 개의 문서가 있다고 가정하자:

Doc ID내용
1블루투스 이어폰 추천
2무선 이어폰 리뷰
3블루투스 스피커 추천

Elasticsearch는 이를 다음과 같이 역인덱스로 저장한다:

역인덱스:
┌─────────────┬────────────────┐
│ Term        │ Document IDs   │
├─────────────┼────────────────┤
│ 블루투스    │ [1, 3]         │
│ 이어폰      │ [1, 2]         │
│ 추천        │ [1, 3]         │
│ 무선        │ [2]            │
│ 리뷰        │ [2]            │
│ 스피커      │ [3]            │
└─────────────┴────────────────┘

“블루투스 이어폰”을 검색하면:

  1. “블루투스” → [1, 3]
  2. “이어폰” → [1, 2]
  3. 교집합: [1] → 문서 1이 가장 관련성 높음

시간 복잡도: O(1) - 문서 수에 관계없이 상수 시간에 검색 가능

Elasticsearch란?

Elasticsearch는 Apache Lucene 기반의 분산형 RESTful 검색 엔진이다.

핵심 특징

특징설명
분산 아키텍처데이터를 여러 노드에 분산 저장, 수평 확장 가능
실시간 검색문서 색인 후 거의 즉시(~1초) 검색 가능
RESTful APIHTTP/JSON 기반으로 모든 언어에서 쉽게 사용
스키마리스유연한 JSON 문서 저장 (동적 매핑)
풍부한 쿼리Full-text, 구조화된 쿼리, 집계, 지리정보 등
고가용성복제본(Replica)으로 장애 대응

첫 번째 쿼리 실행해보기

Elasticsearch가 실행 중이라면, 다음 명령어로 상품을 색인하고 검색할 수 있다:

# 상품 문서 색인
curl -X POST "localhost:9200/products/_doc/1" -H "Content-Type: application/json" -d'
{
  "name": "소니 WH-1000XM5 블루투스 헤드폰",
  "description": "업계 최고의 노이즈 캔슬링 무선 헤드폰",
  "price": 429000,
  "category": "헤드폰"
}'

# 검색
curl -X GET "localhost:9200/products/_search" -H "Content-Type: application/json" -d'
{
  "query": {
    "match": {
      "name": "블루투스 헤드폰"
    }
  }
}'

응답 예시:

{
  "took": 5,
  "hits": {
    "total": { "value": 1 },
    "hits": [
      {
        "_id": "1",
        "_score": 1.2345,
        "_source": {
          "name": "소니 WH-1000XM5 블루투스 헤드폰",
          "description": "업계 최고의 노이즈 캔슬링 무선 헤드폰",
          "price": 429000,
          "category": "헤드폰"
        }
      }
    ]
  }
}

took: 5는 5밀리초 만에 검색이 완료되었음을 의미한다.

Elasticsearch vs RDBMS 비교

용어 매핑

RDBMSElasticsearch설명
DatabaseIndex데이터 저장 공간
TableType (deprecated)7.x 이후 하나의 Index = 하나의 Type
RowDocument하나의 데이터 레코드
ColumnField데이터 속성
SchemaMapping필드 타입 정의
SQLQuery DSL쿼리 언어

언제 무엇을 써야 하나?

사용 사례RDBMSElasticsearch
트랜잭션 (ACID)✅ 적합❌ 부적합
복잡한 JOIN✅ 적합❌ 부적합
실시간 분석/집계⚠️ 제한적✅ 적합
전문 검색⚠️ 제한적✅ 적합
로그 분석❌ 부적합✅ 적합
대시보드⚠️ 제한적✅ 적합

결론: Elasticsearch는 RDBMS를 대체하는 것이 아니라 보완하는 것이다.

일반적인 아키텍처

┌─────────────┐     Write     ┌──────────────┐
│  Application│──────────────▶│   PostgreSQL │ (Source of Truth)
└─────────────┘               └──────────────┘
       │                             │
       │ Search                      │ Sync (CDC/Batch)
       ▼                             ▼
┌─────────────┐               ┌──────────────┐
│   Client    │◀──────────────│ Elasticsearch│ (Search Index)
└─────────────┘    Results    └──────────────┘
  • PostgreSQL: 원본 데이터, 트랜잭션 처리
  • Elasticsearch: 검색 전용 인덱스
  • 동기화: CDC(Change Data Capture) 또는 배치 처리로 데이터 동기화

도입 전 체크리스트

Elasticsearch 도입 전 확인해야 할 사항들:

기술적 요구사항

  • 데이터 규모: 10만 건 이상의 검색 대상 데이터
  • 검색 복잡도: 단순 키워드 매칭 이상의 요구사항
  • 응답 시간: 100ms 이하의 검색 응답 필요
  • 동시 요청: 초당 100 이상의 검색 요청

운영 고려사항

  • 인프라: 최소 3노드 클러스터 권장 (고가용성)
  • 메모리: 노드당 최소 4GB, 권장 16GB+ 힙
  • 스토리지: SSD 필수, 원본 데이터의 1.5~2배 용량
  • 모니터링: Prometheus + Grafana 또는 Elastic Stack

팀 역량

  • 학습 곡선: Query DSL, 매핑, 클러스터 관리 학습 필요
  • 운영 경험: JVM 튜닝, 샤드 관리 경험
  • 장애 대응: 클러스터 복구, 데이터 재색인 절차

OpenSearch와의 관계

2021년 AWS는 Elasticsearch 7.10을 포크하여 OpenSearch를 출시했다. 라이선스 변경(SSPL)에 대한 대응이었다.

공통점

  • 동일한 핵심 엔진 (Lucene 기반)
  • Query DSL 호환 (대부분)
  • REST API 호환

차이점

구분ElasticsearchOpenSearch
라이선스SSPL / Elastic LicenseApache 2.0
관리 주체ElasticAWS + 커뮤니티
클라우드Elastic CloudAWS OpenSearch Service
최신 기능Elasticsearch 우선포크 후 별도 개발

어떤 것을 선택해야 하나?

  • AWS 환경: OpenSearch Service 권장
  • Elastic 에코시스템 필요: Elasticsearch (Kibana, APM 등)
  • 온프레미스/오픈소스 선호: OpenSearch

이 시리즈에서는 Elasticsearch를 기준으로 설명하되, 중요한 차이점은 별도로 표기한다.

마무리

이 글에서 다룬 내용을 정리하면:

  1. RDBMS LIKE 검색의 한계: Full Table Scan으로 인한 성능 저하
  2. 역인덱스의 원리: 단어 → 문서 매핑으로 O(1) 검색
  3. Elasticsearch 특징: 분산, 실시간, RESTful 검색 엔진
  4. 사용 시점: 전문 검색, 로그 분석, 대시보드 등
  5. 아키텍처: RDBMS 보완, 검색 전용 인덱스로 활용

다음 글에서는 Elasticsearch의 클러스터, 노드, 샤드 아키텍처를 자세히 알아본다. 데이터가 어떻게 분산 저장되고, 고가용성은 어떻게 보장되는지 이해하면 프로덕션 운영에 큰 도움이 된다.

참고 자료

다음 글: Elasticsearch 매핑: 필드 타입과 스키마 설계
My avatar

글을 마치며

이 글이 도움이 되었기를 바랍니다. 궁금한 점이나 의견이 있다면 댓글로 남겨주세요.

더 많은 기술 인사이트와 개발 경험을 공유하고 있으니, 다른 포스트도 확인해보세요.

유럽살며 여행하며 코딩하는 노마드의 여정을 함께 나누며, 함께 성장하는 개발자 커뮤니티를 만들어가요! 🚀


Elasticsearch 검색 엔진 마스터 시리즈
Elasticsearch 매핑과 필드 타입 가이드

Elasticsearch 매핑: 필드 타입과 스키마 설계

Elasticsearch의 매핑을 이해하고 올바른 필드 타입을 선택하는 방법을 알아봅니다. text vs keyword, 동적 매핑의 함정, 매핑 폭발 방지, 중첩 객체 처리까지 실무 설계 패턴을 다룹니다.

Elasticsearch OpenSearch 검색엔진 +3
Elasticsearch CRUD와 Bulk API 가이드

Elasticsearch CRUD: 문서 색인과 Bulk API 최적화

Elasticsearch에서 문서를 생성, 조회, 수정, 삭제하는 방법과 대량 데이터 처리를 위한 Bulk API 최적화 전략을 알아봅니다. refresh 동작, 라우팅, 버전 관리까지 실무 팁을 다룹니다.

백엔드 Elasticsearch OpenSearch +3