6 분 소요

Elasticsearch란?

Elasticsearch는 Apache Lucene 기반의 오픈소스 분산 검색 엔진입니다. 구글처럼 빠른 전문 검색을 제공합니다.

일반 데이터베이스 vs Elasticsearch

항목 일반 DB (MySQL 등) Elasticsearch
검색 방식 데이터를 하나씩 찾아봄 모든 텍스트를 미리 색인화
검색 속도 데이터 많을수록 느림 수백만 건도 0.1초 안에
데이터 형식 표(Table) 형태 JSON 문서 형태
주요 용도 거래, 회원 관리 검색, 로그 분석, 모니터링

Apache Lucene이란?

Elasticsearch의 기반이 되는 Apache Lucene은 자바로 작성된 검색 라이브러리입니다.

Lucene vs Elasticsearch

항목 Lucene Elasticsearch
역할 검색 엔진 코어 라이브러리 완성된 검색 플랫폼
사용 방식 자바 코드로 직접 구현 REST API로 간단히 사용
분산 처리 미지원 자동 분산 및 확장
실시간 검색 수동 구현 필요 자동 제공

비유하자면:

  • Lucene = 자동차 엔진
  • Elasticsearch = 완성된 자동차 (엔진 + 편의 기능)

Elasticsearch는 Lucene의 강력한 검색 기능에 분산 처리, REST API, 실시간 검색 등을 더해 누구나 쉽게 사용할 수 있게 만든 플랫폼입니다.

주요 활용 사례

  • E-커머스: 쿠팡, Amazon의 상품 검색
  • 로그 분석: Netflix, Uber의 ELK Stack
  • 콘텐츠 검색: Wikipedia, Medium의 전문 검색
  • 실시간 모니터링: LinkedIn, GitHub의 시스템 추적

Elasticsearch는 왜 빠를까?

Elasticsearch의 빠른 속도 비결은 애널라이저(Analyzer)역인덱스(Inverted Index) 두 가지 핵심 기술에 있습니다.

일반 검색 vs 역인덱스 검색

일반 데이터베이스의 검색 방식:

1
2
3
4
5
6
문서 1: "Apple 맥북 프로 16인치"
문서 2: "Apple 에어팟 프로"
문서 3: "Apple 아이패드 프로"

검색어 입력: "Apple 아이패드"
→ 모든 문서를 하나씩 읽으며 확인 (느림)

Elasticsearch의 역인덱스 방식:

1
2
3
4
5
6
7
8
미리 만들어둔 색인:
Apple     → [문서1, 문서2, 문서3]
맥북      → [문서1]
에어팟    → [문서2]
아이패드  → [문서3]

검색어 입력: "Apple 아이패드"
→ 색인에서 즉시 찾음 (빠름)

동작 원리

graph TD
%% 스타일 정의
    classDef docs fill: #e3f2fd, stroke: #1565c0, stroke-width: 2px, color: #000
    classDef index fill: #fff9c4, stroke: #fbc02d, stroke-width: 2px, color: #000
    classDef search fill: #e8f5e9, stroke: #2e7d32, stroke-width: 2px, color: #000
    classDef result fill: #f3e5f5, stroke: #7b1fa2, stroke-width: 2px, color: #000
%% 1단계
    subgraph Step1 ["1단계: 단어 조각내기 (Tokenization)"]
        D1["문서 1<br/>(Apple, 맥북...)"]:::docs
        D2["문서 2<br/>(Apple, 에어팟...)"]:::docs
        D3["문서 3<br/>(Apple, 아이패드...)"]:::docs
    end

%% 2단계
    subgraph Step2 ["2단계: 거꾸로 정리하기 (Inverted Index)"]
        IndexTable[/"<b>역인덱스 (색인) 목록</b><br/>-----------------------------<br/><b>Apple</b> -> [1, 2, 3] (흔함)<br/><b>에어팟</b> -> [2]<br/><b>아이패드</b> -> [3] (희귀함)"/]:::index
    end

%% 3단계
    subgraph Step3 ["3단계: 검색 및 점수 매기기 (Scoring)"]
        Query["검색어 입력:<br/>'Apple' + '아이패드'"]:::search
        Calculation{"점수 계산"}:::search
        Result["<b>최종 결과 순위</b><br/>🥇 1위: 문서 3 (2단어 일치)<br/>🥈 2위: 문서 1, 2 (1단어 일치)"]:::result
    end

%% 연결선
    Step1 ==> Step2
    Step2 -.-> Calculation
    Query --> Calculation
    Calculation --> Result

Elasticsearch는 이렇게 동작합니다:

  1. 애널라이저가 문서를 토큰으로 분리 (Apple, 맥북, 에어팟 등)
  2. 역인덱스에 토큰별로 문서 목록 저장 (Apple → [1,2,3])
  3. 검색 시 역인덱스에서 즉시 찾고 관련도 점수 계산

이 방식 덕분에 수백만 건의 데이터에서도 0.1초 안에 검색이 가능합니다.

핵심 용어 정리 (MySQL과 비교)

용어 대응표

개념 MySQL Elasticsearch 의미
저장소 테이블 (Table) 인덱스 (Index) 데이터가 저장되는 가장 큰 틀
데이터 한 건 행 (Row) 도큐먼트 (Document) 실제 저장되는 데이터 개체
데이터 속성 컬럼 (Column) 필드 (Field) 데이터의 각 항목
구조 정의 스키마 (Schema) 매핑 (Mapping) 데이터 타입 및 구조 정의

1. 인덱스 (Index)

MySQL의 테이블과 같은 개념입니다.

1
2
3
MySQL:         users 테이블
                ↓
Elasticsearch: users 인덱스

2. 도큐먼트 (Document)

MySQL의 행(Row)과 같은 개념으로, JSON 형식으로 저장됩니다.

1
2
3
4
5
6
{
  "product_name": "맥북 프로 16인치",
  "price": 3500000,
  "category": "노트북",
  "brand": "Apple"
}

3. 필드 (Field)

MySQL의 컬럼(Column)과 같으며, 도큐먼트의 각 속성입니다.

위 예시에서 product_name, price, category, brand가 모두 필드입니다.

4. 매핑 (Mapping)

MySQL의 스키마처럼 데이터 타입을 정의하는 설계도입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
  "properties": {
    "product_name": {
      "type": "text"
    },
    "price": {
      "type": "integer"
    },
    "brand": {
      "type": "keyword"
    },
    "created_at": {
      "type": "date"
    }
  }
}

text vs keyword 차이

  • text: 전문 검색용 (형태소 분석됨)
  • keyword: 정확히 일치 검색용 (필터링, 정렬에 사용)

Elasticsearch REST API

MySQL은 SQL 문법을 사용하지만, Elasticsearch는 HTTP 메서드로 작업합니다.

전체 흐름

1
2
3
4
5
6
7
1. 인덱스 생성 (CREATE TABLE과 동일)
   ↓
2. 매핑 정의 (컬럼 타입 지정과 동일)
   ↓
3. 데이터 삽입 (INSERT와 동일)
   ↓
4. 데이터 조회 (SELECT와 동일)

STEP 1: 인덱스 관리

인덱스 생성

1
PUT /products

MySQL 비교:

1
CREATE TABLE products;

예상 응답:

1
2
3
4
5
{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "products"
}

인덱스 조회

1
GET /products

인덱스 삭제

1
DELETE /products

STEP 2: 매핑 정의

인덱스를 만들었다면, 이제 어떤 데이터가 들어갈지 정의해야 합니다.

1
PUT /products/_mapping

요청 본문:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "properties": {
    "product_name": {
      "type": "text"
    },
    "price": {
      "type": "integer"
    },
    "stock": {
      "type": "integer"
    },
    "is_available": {
      "type": "boolean"
    },
    "brand": {
      "type": "keyword"
    },
    "created_at": {
      "type": "date"
    }
  }
}

MySQL 비교:

1
2
3
4
5
6
7
8
9
CREATE TABLE products
(
    product_name VARCHAR(255),
    price        INT,
    stock        INT,
    is_available BOOLEAN,
    brand        VARCHAR(100),
    created_at   DATETIME
);

STEP 3: 도큐먼트 삽입

이제 실제 데이터를 넣어봅시다.

1
POST /products/_doc

요청 본문:

1
2
3
4
5
6
7
8
{
  "product_name": "맥북 프로 16인치 M3",
  "price": 3500000,
  "stock": 50,
  "is_available": true,
  "brand": "Apple",
  "created_at": "2024-11-30"
}

MySQL 비교:

1
2
INSERT INTO products (product_name, price, stock, is_available, brand, created_at)
VALUES ('맥북 프로 16인치 M3', 3500000, 50, true, 'Apple', '2024-11-30');

예상 응답:

1
2
3
4
5
6
{
  "_index": "products",
  "_id": "xA7bK4oBXXXXXXXXXXXX",
  "_version": 1,
  "result": "created"
}

STEP 4: 데이터 조회

전체 데이터 조회

1
GET /products/_search

MySQL 비교:

1
2
SELECT *
FROM products;

예상 응답:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "took": 2,
  "hits": {
    "total": {
      "value": 1
    },
    "hits": [
      {
        "_index": "products",
        "_id": "xA7bK4oBXXXXXXXXXXXX",
        "_score": 1.0,
        "_source": {
          "product_name": "맥북 프로 16인치 M3",
          "price": 3500000,
          "stock": 50,
          "is_available": true,
          "brand": "Apple",
          "created_at": "2024-11-30"
        }
      }
    ]
  }
}

특정 조건으로 검색

1
GET /products/_search

요청 본문:

1
2
3
4
5
6
7
{
  "query": {
    "match": {
      "product_name": "맥북"
    }
  }
}

MySQL 비교:

1
2
3
SELECT *
FROM products
WHERE product_name LIKE '%맥북%';

응답 데이터 이해하기

필드 의미 설명
_index 인덱스 이름 어느 인덱스에서 온 데이터인지
_id 문서 ID MySQL의 Primary Key와 유사
_score 관련도 점수 검색어와 얼마나 관련이 있는지 (높을수록 관련도 높음)
_source 실제 데이터 우리가 저장한 JSON 문서

애널라이저(Analyzer)란?

애널라이저는 Elasticsearch가 텍스트를 검색 가능한 토큰으로 변환하는 3단계 공정입니다.

애널라이저의 3단계 공정

graph LR
    A["원문<br/>'Apple 2025 맥북'"] --> B["1단계: 세척<br/>(Character Filter)"]
    B --> C["2단계: 절단<br/>(Tokenizer)"]
    C --> D["3단계: 가공<br/>(Token Filter)"]
    D --> E["최종 토큰<br/>['apple', '2025', '맥북']"]
    style A fill: #e3f2fd
    style B fill: #fff9c4
    style C fill: #ffe0b2
    style D fill: #f8bbd0
    style E fill: #c8e6c9

1단계: Character Filter (세척)

토큰으로 자르기 전에 불필요한 부분을 제거하거나 변경합니다.

예시:

1
2
3
입력: "<h1>Apple 맥북</h1>"
     ↓ (HTML 태그 제거)
출력: "Apple 맥북"

주요 역할:

  • HTML 태그 제거
  • 특수 문자 변환
  • 특정 패턴 치환

2단계: Tokenizer (절단)

문장을 단어 단위로 잘라냅니다.

예시:

1
2
3
입력: "Apple 맥북 프로"
     ↓ (공백 기준으로 절단)
출력: ["Apple", "맥북", "프로"]

주요 역할:

  • 공백으로 단어 분리
  • 문장 부호로 분리
  • 언어별 형태소 분석

3단계: Token Filter (가공)

토큰들을 검색에 최적화된 형태로 변환합니다.

예시:

1
2
3
입력: ["Apple", "is", "running"]
     ↓ (소문자 변환 + 불용어 제거 + 어간 추출)
출력: ["apple", "run"]

주요 역할:

  • 소문자 변환
  • 불용어 제거
  • 어간 추출
  • 동의어 처리

Standard Analyzer (기본값)

단계 필터/토크나이저 역할
Character Filter 없음 세척 안 함
Tokenizer Standard Tokenizer 공백과 문장 부호로 자름
Token Filter Lowercase Filter 소문자로 변환

실제 동작 예시

1
2
3
4
5
6
7
입력: "Apple 2025 맥북"

1단계 (Character Filter): "Apple 2025 맥북" (변화 없음)
2단계 (Tokenizer):        ["Apple", "2025", "맥북"]
3단계 (Token Filter):     ["apple", "2025", "맥북"]

최종 토큰: ["apple", "2025", "맥북"]

애널라이저 테스트하기

1
POST /_analyze

요청 본문:

1
2
3
4
{
  "analyzer": "standard",
  "text": "Apple 2025 맥북 프로!"
}

응답:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "tokens": [
    {
      "token": "apple",
      "start_offset": 0,
      "end_offset": 5,
      "position": 0
    },
    {
      "token": "2025",
      "start_offset": 6,
      "end_offset": 10,
      "position": 1
    },
    {
      "token": "맥북",
      "start_offset": 11,
      "end_offset": 13,
      "position": 2
    },
    {
      "token": "프로",
      "start_offset": 14,
      "end_offset": 16,
      "position": 3
    }
  ]
}

정리

  • Elasticsearch는 Apache Lucene 기반의 검색 엔진으로, 누구나 쉽게 사용할 수 있게 만든 플랫폼
  • 애널라이저가 텍스트를 토큰으로 변환하고, 역인덱스에 저장하여 빠른 검색 실현
  • MySQL의 Table/Row/Column은 Elasticsearch의 Index/Document/Field에 대응
  • REST API로 간단히 CRUD 작업 수행

댓글남기기