본문으로 건너뛰기
홈
기술
기술 전체
프로그래밍68
컴퓨터 과학63
AI48
웹 개발36
인프라33
데이터31
소프트웨어 공학18
소개
← 목록으로데이터 › 검색 › Elasticsearch

엘라스틱 스택

목차

엘라스틱 스택 구조

  • 시각화 : 키바나
  • 데이터 저장 & 검색 엔진 : 엘라스틱 서치
  • 데이터 수집 : 비츠, 로그스태시

엘라스틱 서치

  • 검색 엔진으로 각 도큐먼트를 인덱싱하고 빠르게 검색하는데 사용하는 기술
  • 모든 레코드를 JSON 도큐먼트 형태로 입력하고 관리

단점

  • 저장공간이 크게 압축되지 않고 시스템 리소스를 많이 사용
  • DSL 쿼리를 사용하여 Join 쿼리가 사실상 어렵고 반정규화를 기본으로 모델링
  • 인덱스가 불변의 자료구조이므로 도큐먼트를 수정하거나 삭제할 경우 비용이 비싸다

데이터가 이동하는 길

flowchart LR
  원본[애플리케이션·로그] --> 수집[Beats / Logstash]
  수집 --> 저장[Elasticsearch 인덱스]
  저장 --> 탐색[Kibana 시각화]

Beats는 데이터를 수집하고 전달하며, Logstash는 입력을 받아 변환하고 출력할 수 있다. 모든 구성에 두 도구가 다 필요한 것은 아니다. 애플리케이션이 Elasticsearch API로 직접 도큐먼트를 보낼 수도 있다.

Elasticsearch의 인덱스는 비슷한 도큐먼트가 들어가는 논리적 공간이다. 도큐먼트는 JSON 형태이며 필드가 검색에 어떻게 쓰이는지는 매핑이 결정한다. text 필드는 분석을 거쳐 전문 검색에, keyword 필드는 정확한 값 비교나 집계에 주로 쓴다. 같은 문자열이라도 검색 목적에 따라 필드 타입을 정해야 한다.

원본 데이터베이스의 복잡한 조인을 그대로 옮기려 하기보다 검색 화면에서 필요한 필드를 도큐먼트에 함께 담는 방식을 검토한다. 수정과 삭제에도 내부 재색인 비용이 발생할 수 있으므로, 쓰기 빈도와 검색 요구를 함께 측정해 설계한다.

검색 요청 예시

products 인덱스에 이름 필드가 있는 도큐먼트를 저장했다면 다음처럼 match 쿼리로 검색할 수 있다.

{
  "query": {
    "match": { "name": "무선 키보드" }
  }
}

이 JSON은 검색 API의 요청 본문 예시다. match는 필드의 분석 설정을 사용하므로 입력 문자열 전체가 정확히 일치하는 조건과 다르다. 상품 코드처럼 정확히 같은 값만 찾으려면 매핑에 맞는 keyword 필드와 term 쿼리를 살펴본다. 검색 결과의 점수나 형태는 분석기와 매핑에 따라 달라지므로 실제 데이터로 확인해야 한다.

이 스택을 도입할 때는 원본 데이터가 어디에 있고, 변경이 언제 Elasticsearch에 반영되며, 재색인이 필요하면 어떻게 다시 채울지 정한다. 검색용 사본만 두고 원본과의 동기화 경로가 없으면 오래된 정보가 검색 결과에 남을 수 있다.

매핑을 먼저 결정해야 하는 이유

상품 검색을 예로 들면 name은 단어로 검색하고 sku는 정확한 코드로 찾는다. 둘 다 문자열이라고 같은 매핑을 쓰면 결과가 달라진다. text는 분석기가 입력을 토큰으로 나누어 전문 검색에 사용한다. keyword는 값 전체를 기준으로 필터·정렬·집계하기 좋다. 다음 요청은 Kibana Dev Tools 콘솔에 입력하는 예시다. 이미 같은 이름의 인덱스가 있다면 새 이름을 사용한다.

PUT /products-lab
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "sku": { "type": "keyword" },
      "price": { "type": "integer" }
    }
  }
}

PUT /products-lab/_doc/p1
{ "name": "무선 키보드", "sku": "KB-100", "price": 59000 }

GET /products-lab/_search
{
  "query": { "match": { "name": "무선 키보드" } }
}

검색 결과의 _hits에는 일치한 도큐먼트와 관련도 점수가 나타난다. 정확한 SKU 조건에는 term 쿼리를 사용한다.

GET /products-lab/_search
{
  "query": { "term": { "sku": "KB-100" } }
}

term을 분석된 name에 그대로 적용하면 예상한 전체 단어 검색이 되지 않을 수 있다. 한 필드를 검색과 정확 일치 양쪽에 쓰려면 text와 keyword 하위 필드를 가진 multi-field 매핑을 고려한다. 한국어의 조사·복합어 처리도 분석기 선택에 영향을 받으므로 실제 검색어로 _analyze 결과와 검색 결과를 확인한다.

수집부터 검색까지에서 생기는 지연

flowchart LR
  D[원본 DB·애플리케이션] --> E[수집·변환]
  E --> I[Elasticsearch 인덱싱]
  I --> S[검색 API]
  S --> K[Kibana 또는 서비스 화면]
  D -.변경·삭제 이벤트.-> E

원본 데이터가 변경돼도 수집 파이프라인이 실패하거나 지연되면 검색 인덱스에는 예전 값이 남는다. “Elasticsearch에 넣었다”는 것만으로 검색 가능한 최신 상태가 됐다고 판단하지 않는다. 수집 오류, 인덱싱 실패, 검색 응답 시각을 따로 관찰한다. Elasticsearch의 인덱싱은 기본적으로 near real-time 모델이므로 쓰기 직후 검색에 보이는 시점에도 차이가 있다. 이 때문에 결제 잔액처럼 즉시 일치가 필요한 원장 조회를 검색 인덱스 하나로 대체하기는 어렵다.

원문에서 “인덱스가 불변이라 도큐먼트 수정이 비싸다”는 표현은 Lucene 세그먼트의 특성에서 나온 말이다. API에서는 도큐먼트 업데이트·삭제를 지원한다. 내부적으로 새 버전의 인덱싱과 세그먼트 병합 등의 비용이 발생할 수 있다는 뜻으로 이해한다. “Join이 사실상 어렵다” 역시 관계형 DB의 임의 조인과 동일한 사용 경험이 아니라는 설명으로 제한해야 한다. nested·parent-child 등 관계 표현 방식이 있지만 복잡성과 조회 비용이 있어 검색 요구에 맞게 모델링한다.

증상점검 순서
문서가 검색되지 않음인덱스 이름 → 인덱싱 응답 → refresh 시점 → 매핑·분석기
예상보다 많은 결과match의 분석·관련도 기준과 정확 일치 요구 구분
집계가 안 됨대상 필드가 keyword 또는 숫자형인지
오래된 값 노출원본 변경 이벤트, 수집 실패, 재색인 절차

검색용 데이터는 원본과 별도의 사본일 수 있다. 운영에서는 샤드·복제본·저장 기간·접근 권한·백업 정책을 데이터 규모에 맞춰 정하고, 적은 데이터라면 먼저 기존 DB의 검색 기능으로 충분한지도 비교한다.

참고: Elastic text 필드, keyword 필드, match 쿼리, 인덱싱과 refresh.