Elasticsearch 실전 가이드 | 검색·인덱싱·Aggregation·성능 최적화

Elasticsearch 실전 가이드 | 검색·인덱싱·Aggregation·성능 최적화

이 글의 핵심

Elasticsearch로 강력한 검색 엔진을 구축하는 실전 가이드입니다. 인덱싱, 쿼리, Aggregation, 분석기, 성능 최적화까지 실무 예제로 정리했습니다.

실무 경험 공유: 이커머스 상품 검색을 Elasticsearch로 구축하면서, 검색 속도를 10배 향상시키고 오타 허용 검색으로 전환율을 30% 높인 경험을 공유합니다.

들어가며: “데이터베이스 검색이 느려요”

실무 문제 시나리오

시나리오 1: LIKE 쿼리가 10초 걸려요
PostgreSQL LIKE 검색이 느립니다. Elasticsearch는 0.1초입니다.

시나리오 2: 오타를 허용하고 싶어요
정확한 검색어만 찾습니다. Elasticsearch는 Fuzzy Search를 지원합니다.

시나리오 3: 복잡한 집계가 필요해요
카테고리별 상품 수, 가격 범위 등을 계산해야 합니다. Elasticsearch Aggregation으로 해결합니다.


1. Elasticsearch란?

핵심 특징

Elasticsearch는 분산 검색 및 분석 엔진입니다.

주요 사용 사례:

  • 전문 검색: 상품, 문서, 로그 검색
  • 자동완성: 실시간 검색어 제안
  • 분석: 로그 분석, 메트릭 집계
  • 추천: 유사 문서 찾기

성능:

  • 검색 속도: < 100ms
  • 인덱싱: 10,000+ docs/sec

2. 설치

Docker

docker run -d \
  --name elasticsearch \
  -p 9200:9200 \
  -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=false" \
  docker.elastic.co/elasticsearch/elasticsearch:8.12.0

확인

curl http://localhost:9200

3. 인덱싱

인덱스 생성

# 인덱스 생성
curl -X PUT "localhost:9200/products" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "description": { "type": "text" },
      "price": { "type": "float" },
      "category": { "type": "keyword" },
      "tags": { "type": "keyword" },
      "created_at": { "type": "date" }
    }
  }
}
'

문서 추가

# 단일 문서
curl -X POST "localhost:9200/products/_doc" -H 'Content-Type: application/json' -d'
{
  "name": "Laptop",
  "description": "High performance laptop",
  "price": 1200.00,
  "category": "Electronics",
  "tags": ["laptop", "computer"],
  "created_at": "2026-04-30"
}
'

# Bulk 추가
curl -X POST "localhost:9200/_bulk" -H 'Content-Type: application/json' -d'
{"index":{"_index":"products"}}
{"name":"Mouse","price":25.00,"category":"Electronics"}
{"index":{"_index":"products"}}
{"name":"Keyboard","price":75.00,"category":"Electronics"}
'

4. 검색 쿼리

Match Query

curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "name": "laptop"
    }
  }
}
'

Multi Match

curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "multi_match": {
      "query": "laptop",
      "fields": ["name^2", "description"]
    }
  }
}
'

Bool Query (복합 조건)

curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        { "match": { "category": "Electronics" } }
      ],
      "filter": [
        { "range": { "price": { "gte": 100, "lte": 1000 } } }
      ],
      "should": [
        { "match": { "tags": "laptop" } }
      ]
    }
  }
}
'

Fuzzy Search (오타 허용)

curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "fuzzy": {
      "name": {
        "value": "lapto",
        "fuzziness": "AUTO"
      }
    }
  }
}
'

5. Aggregation

Terms Aggregation (그룹화)

curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": {
        "field": "category"
      }
    }
  }
}
'

Stats Aggregation (통계)

curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "price_stats": {
      "stats": {
        "field": "price"
      }
    }
  }
}
'

Histogram (히스토그램)

curl -X GET "localhost:9200/products/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "price_ranges": {
      "histogram": {
        "field": "price",
        "interval": 100
      }
    }
  }
}
'

6. Node.js 클라이언트

설치

npm install @elastic/elasticsearch

사용

import { Client } from '@elastic/elasticsearch';

const client = new Client({
  node: 'http://localhost:9200',
});

// 검색
async function searchProducts(query: string) {
  const result = await client.search({
    index: 'products',
    body: {
      query: {
        multi_match: {
          query,
          fields: ['name^2', 'description'],
        },
      },
    },
  });

  return result.hits.hits.map((hit) => hit._source);
}

// 인덱싱
async function indexProduct(product: any) {
  await client.index({
    index: 'products',
    body: product,
  });
}

// 자동완성
async function autocomplete(prefix: string) {
  const result = await client.search({
    index: 'products',
    body: {
      query: {
        match_phrase_prefix: {
          name: prefix,
        },
      },
      size: 5,
    },
  });

  return result.hits.hits.map((hit) => hit._source.name);
}

7. 분석기 (Analyzer)

한글 분석기

# nori 플러그인 설치
bin/elasticsearch-plugin install analysis-nori
curl -X PUT "localhost:9200/products_kr" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "analysis": {
      "analyzer": {
        "korean": {
          "type": "custom",
          "tokenizer": "nori_tokenizer",
          "filter": [lowercase]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "korean"
      }
    }
  }
}
'

8. 성능 최적화

Bulk API

// 대량 인덱싱
async function bulkIndex(products: any[]) {
  const body = products.flatMap((doc) => [
    { index: { _index: 'products' } },
    doc,
  ]);

  await client.bulk({ body });
}

캐싱

curl -X PUT "localhost:9200/products/_settings" -H 'Content-Type: application/json' -d'
{
  "index": {
    "requests.cache.enable": true
  }
}
'

Refresh Interval

# 실시간 검색이 필요 없으면 interval 증가
curl -X PUT "localhost:9200/products/_settings" -H 'Content-Type: application/json' -d'
{
  "index": {
    "refresh_interval": "30s"
  }
}
'

정리 및 체크리스트

핵심 요약

  • Elasticsearch: 분산 검색 및 분석 엔진
  • 전문 검색: 빠르고 정확한 검색
  • Fuzzy Search: 오타 허용
  • Aggregation: 강력한 집계
  • 분석기: 다국어 지원
  • 확장성: 수평 확장 가능

프로덕션 체크리스트

  • Elasticsearch 클러스터 구성
  • 인덱스 매핑 설계
  • 분석기 설정
  • 검색 쿼리 최적화
  • Aggregation 구현
  • 모니터링 설정
  • 백업 자동화

같이 보면 좋은 글

  • MongoDB 고급 가이드
  • Redis 고급 가이드
  • PostgreSQL 고급 가이드

이 글에서 다루는 키워드

Elasticsearch, Search, Full-Text Search, Indexing, Analytics, ELK Stack

자주 묻는 질문 (FAQ)

Q. Elasticsearch vs PostgreSQL Full-Text Search, 어떤 게 나은가요?

A. Elasticsearch가 훨씬 빠르고 기능이 많습니다. 복잡한 검색은 Elasticsearch, 간단한 검색은 PostgreSQL을 권장합니다.

Q. 메모리를 많이 사용하나요?

A. 네, 인메모리 캐싱을 많이 사용합니다. 최소 4GB RAM을 권장합니다.

Q. 클러스터 구성이 필수인가요?

A. 아니요, 단일 노드로도 사용 가능합니다. 하지만 프로덕션에서는 최소 3노드 클러스터를 권장합니다.

Q. Kibana는 뭔가요?

A. Elasticsearch 데이터를 시각화하는 도구입니다. 대시보드, 차트를 만들 수 있습니다.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3