ELK & Elastic Cloud

Elasticsearch란

meellon 2026. 7. 2. 12:00

학습 목표

Elasticsearch분산 검색·분석 엔진으로 무엇을 하는지 설명할 수 있다.

document·index·_id·_source의 관계를 설명할 수 있다.

inverted index가 full-text 검색에 쓰이는 이유를 설명할 수 있다.

near real-time(NRT) 에서 index 직후 검색이 즉시 되지 않는 이유를 설명할 수 있다.

기본 Index·Get·Search REST API로 document를 넣고 조회할 수 있다.

문제 상황

  • JSON 로그를 Elasticsearch에 넣었는데 Kibana에서 안 보인다 — refresh 전이라 NRT 타이밍
  • orders 테이블처럼 생각하고 UPDATE 했더니 새 document가 생김 — document 불변·append 모델
  • message 필드만 검색하면 되는데 모든 필드를 keyword로 잡아 디스크가 터진다 — mapping은 3편
  • GET /logs/_search 결과에 _score가 있는데 정렬 기준이 뭔지 모르겠다
  • RDB LIKE '%error%'풀 스캔 — ES는 inverted index로 빠르게 찾는다고 하는데 구조를 모름
  • 오리엔테이션에서 index·search 축만 봤고, document가 어떻게 저장·검색되는지는 처음

앞 편에서 Elastic Stack 데이터 흐름을 봤다. 이번 편은 Elasticsearch 코어 — document·index·inverted index·NRT. mapping·analyzer는 3편, Query DSL은 4편이다.

1. Elasticsearch란?

  • Elasticsearch (ES)
    • 분산 document 저장소 + full-text 검색 + 집계(aggregation) 엔진
    • Apache Lucene 위에 REST API·클러스터 조율·운영 기능을 얹은 Elastic Stack의 중심
  • 주 용도
    • 로그·이벤트 검색 (ELK의 L 저장소)
    • 앱 검색, 메트릭·APM 데이터, 보안 이벤트(SIEM)
  • RDB와 다른 점
    • 스키마는 mapping으로 유연(동적 mapping 가능) — 3편
    • JOIN은 제한적 — denormalize·nested·parent-child는 특수 케이스
    • 트랜잭션 단위가 document — row 단위 ACID와 다름
  RDB Elasticsearch
단위 row document (JSON)
조회 SQL Query DSL / KQL
full-text LIKE, full scan inverted index
스케일 수직·샤딩 수동 shard·replica 기본 (5편)
업데이트 in-place UPDATE reindex·update API (내부는 새 버전)

2. Document와 Index

데이터는 JSON document로 저장된다.

Document

  • document — ES가 인덱싱·검색하는 최소 단위 (JSON 객체)
  • _id — document 식별자 (직접 지정 또는 자동 생성)
  • _source — 원본 JSON 본문
  • metadata_index, _id, _version, _score(검색 시) 등
{
  "@timestamp": "2026-07-18T06:00:01.123Z",
  "level": "ERROR",
  "service": "order-api",
  "message": "payment timeout",
  "order_id": 9001,
  "trace_id": "a1b2c3d4e5f6"
}
  • 로그·이벤트는 한 줄(한 이벤트) = 한 document가 자연스럽다
  • 앞서 구조화 로그 필드(level, trace_id)가 그대로 ES 필드가 됨

Index

  • index — document의 논리적 컬렉션 (RDB table에 대응하기 쉽지만 동일하지 않음)
  • 이름 예: logs-order-prod, metrics-k8s-2026.07
  • 한 document는 한 index에 속함 (_index 메타데이터)
  • 물리적으로 index는 shard로 나뉨 — 5편에서 cluster·routing
index: app-logs
  ├── doc _id=1  { level: INFO,  message: "started" }
  ├── doc _id=2  { level: ERROR, message: "timeout" }
  └── doc _id=3  { level: WARN,  message: "retry" }
  • index vs data stream — 최신 로그는 data stream 권장 (9편). 개념은 동일하게 document 집합

3. Inverted Index

full-text 검색의 핵심 자료구조.

동작

  • 정방향 — document → 필드 텍스트
  • 역방향(inverted)term(단어) → 어떤 document에 있는지 posting list
Doc 1: "payment timeout error"
Doc 2: "payment succeeded"
Doc 3: "timeout retry"

term          →  doc ids
payment       →  1, 2
timeout       →  1, 3
error         →  1
succeeded     →  2
retry         →  3
  • 검색 timeout — posting list {1, 3} 즉시 조회 — 전체 document 스캔 불필요
  • analyzer가 텍스트를 term으로 쪼갬 — 소문자·형태소·동의어 (3편)
  • text — analyzed, full-text 검색용
  • keyword — analyzed 안 함, 정확 일치·필터·집계용 (3편)
질문 inverted index
"error 포함 로그" term error posting
"payment AND timeout" 두 posting list 교집합
order_id=9001 keyword/long 필드 — B-tree 유사 doc values
  • 집계(aggregation) 는 often doc values (columnar) 사용 — 5편

4. Near Real-Time 검색

index API 직후 바로 검색 안 될 수 있다NRT 모델.

Index request
    → in-memory buffer (빠른 쓰기)
    → refresh (기본 ~1s) → new segment (searchable)
    → eventual merge to larger segments
단계  
Index document를 메모리 버퍼에 기록 — 아직 검색 불가일 수 있음
Refresh 버퍼를 segment로 만들어 searchable — 기본 index.refresh_interval 1s
Flush segment를 디스크에 확정 — 트랜잭션 로그 정리
Merge 작은 segment 병합 — 백그라운드, 검색은 계속 가능
  • trade-off
    • refresh 짧게 — 검색 지연↓, CPU·I/O↑
    • bulk ingest 시 refresh_interval=-1로 끄고 끝에 한 번 refresh — 대량 적재 패턴
  • GET /index/_refresh — 수동 refresh (테스트·배치 후)
  • RDB commit 직후 SELECT와 달리 — 1초 내 보이면 NRT로 충분한 경우가 많음 (로그·대시보드)

5. 기본 REST API

클러스터 URL을 http://localhost:9200 으로 가정.

Index (생성·적재)

# 자동 _id
curl -X POST "localhost:9200/app-logs/_doc" \
  -H "Content-Type: application/json" \
  -d '{
    "@timestamp": "2026-07-18T06:00:01Z",
    "level": "ERROR",
    "service": "order-api",
    "message": "payment timeout",
    "order_id": 9001
  }'

# _id 지정
curl -X PUT "localhost:9200/app-logs/_doc/order-9001-error" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
  • _doc — document 타입 (7.x+ 타입 제거, _doc 관례)
  • 응답: "result": "created" / "updated", _id, _version

Get (단건 조회)

curl "localhost:9200/app-logs/_doc/order-9001-error"
  • _source에 원본 JSON — 검색 없이 ID로 직접 fetch (routing·shard — 5편)

Search (검색)

curl -X POST "localhost:9200/app-logs/_search" \
  -H "Content-Type: application/json" \
  -d '{
    "query": {
      "match": { "message": "timeout" }
    },
    "size": 10
  }'
  • hits.hits[] — 매칭 document + _score(관련도)
  • match — analyzed 필드 full-text — 4편에서 bool·filter·pagination
  • Kibana Discover도 동일 index에 Query DSL / KQL 전송

Bulk (대량 적재)

curl -X POST "localhost:9200/_bulk" \
  -H "Content-Type: application/x-ndjson" \
  --data-binary @code/bulk-logs.ndjson
  • 한 HTTP 요청에 여러 index — ingest 성능의 기본 (Beats·Logstash도 bulk 사용)

6. 실무에서 기억할 점

주제 이번 편 이후
필드 타입·analyzer 개념만 3편 mapping
쿼리·필터·정렬 match 맛보기 4편 Query DSL
shard·replica·routing index에 존재 5편 cluster
data stream classic index 먼저 9편
보안·인증 생략 20편
  • document 설계 — 검색·집계할 필드를 미리 JSON 키로 (구조화 로그)
  • 고카디널리티trace_id검색에, keyword 인덱싱 남발은 비용 (Observability·3편)
  • index 이름 — env·서비스·날짜 패턴 (logs-order-prod-2026.07.18) — ILM·template과 연계 (13~14편)

정리

  • Elasticsearch — JSON document 저장 + inverted index 검색 + 집계
  • index — document 논리 집합; 물리적으로 shard에 분산
  • inverted index — term → document 목록; full-text의 속도 근원
  • NRT — refresh 후 searchable; 기본 ~1s 지연 각오
  • Index / Get / Search / Bulk — 스택 전반(Beats·Kibana)의 기반 API

다음에 다룰 것

  • Mapping과 Analyzer
  • field type, dynamic mapping, text vs keyword, analyzer

해당 내용은 Elasticsearch Guide (Documents and indices, Near real-time search) 를 기반으로 합니다.

'ELK & Elastic Cloud' 카테고리의 다른 글

Beats  (0) 2026.07.11
Aggregation과 클러스터  (0) 2026.07.08
Query DSL  (0) 2026.07.05
Mapping과 Analyzer  (0) 2026.07.03
ELK · Elastic Cloud 오리엔테이션  (0) 2026.06.30