~/tech-blog/posts/es-intro — zsh

ElasticSearch를 도입하게 된 이유

대량 거래 데이터에서 여러 조건을 조합해 이상 건을 찾아내는 작업을 진행하는데, 데이터 조건이 너무 많고 다양한 사유로 RDBMS의 Index로는 한계가 존재하였습니다. 때문에 이를 해결하기 위해 ElasticSearch를 적용하게 되었습니다.

ElasticSearch를 적용하면 빠른 이유는 아래와 같습니다.

  1. 역인덱스
    • RDB는 문서 → 내용 방향이지만, 역인덱스는 단어 → 그 단어를 가진 문서를 조회
Term Dictionary        Posting List
"kafka"        →  [1, 5, 8, 13, 21, ...]
"spring"       →  [3, 5, 8, 40, ...]
"redis"        →  [2, 8, 19, ...]

kafka & spring 검색시 Posting List의 5번을 노출해줌으로서 매우 빠르고 속도 또한 O(1)에 가깝습니다.

만약 MySQL기준으로 조회를 한다면 WHERE content LIKE '%kafka%' 와 같은 형태가 될 것이며, 이렇게 될 시 B-tree index를 사용하지 못하여 풀스캔이 발동될 것입니다.

  1. 색인 시점의 분석(Analysis)
    • "미리 해두는 것"
"Kafka를 사용한 Spring Boot 애플리케이션"
  → character filter (HTML 제거 등)
  → tokenizer (형태소 분석 / standard / nori 등)
  → token filter (소문자화, 불용어 제거, 어간 추출, 동의어)
  → [kafka, 사용, spring, boot, 애플리케이션]

위와 같은 문장을 저장할 때 미리 해당하는 Analysis를 사용하여 변환하여 저장해 놓습니다.

대소문자 무시, 어미 변형("running" → "run"), 동의어("노트북" = "랩탑") 처리가 전부 검색 시점이 아니라 색인 시점에 완료합니다.

역색인으로 인한 장점

  1. Term dictionary 탐색이 O(log n) 이하
    • term들이 사전순 정렬되어 있고, Lucene은 여기에 FST(Finite State Transducer)를 씁니다.

💡 term들이 사전순 정렬되어 있다는 것은 무슨 의미일까요?

term들이 사전순 정렬 → FST로 접두사 공유 → 메모리에 올릴 수 있음 → 디스크 seek 없이 오프셋 획득. 역인덱스에 저장된 단어들이 강아지고양이나무 순으로 줄 세워져 있다는 뜻입니다.

왜 굳이 정렬해 두냐면, 정렬돼 있어야 "안 보고 건너뛰기"가 가능하기 때문입니다. 사전에서 "고양이"를 찾을 때 1페이지부터 넘기지 않습니다. 중간을 펴서 "나"가 나오면 "아, 뒤쪽은 안 봐도 되겠다"하고 앞쪽만 봅니다. 정렬이 안 돼 있으면 이 판단 자체가 불가능해서 전부 다 봐야 합니다.

추가적으로 디스크 seek 없이 오프셋을 획득한다는 것은 아래 두 번째 의미인 메모리 힙에 올려둘 수 있다는 것과 이어집니다.

  1. FST는 공통 접두사를 공유하는 상태 기계

    • 사전 본문(= 실제 단어 목록과 뜻)은 두껍고 무겁습니다. 그래서 맨 뒤에 붙은 얇은 색인 페이지를 따로 만듭니다.

      ㄱ ..... 3쪽
      ㄴ ..... 88쪽
      ㄷ ..... 140쪽
      

      FST가 바로 이 색인 페이지 역할입니다. 그런데 그냥 목록이 아니라, 압축돼 있습니다.

      강아지, 강물, 강당 세 단어를 저장할 때 을 세 번 쓰지 않고 한 번만 쓰고 셋이 나눠 씁니다. 아파트 현관문 하나를 여러 집이 공유하듯이요. 단어가 많아질수록 겹치는 부분도 많아지니, 절약되는 양이 눈덩이처럼 커집니다.

  2. 메모리 사용량이 작아서 힙에 올려둘 수 있습니다.

    • 색인 페이지가 압축 덕분에 아주 얇아졌으니, 메모리에 올릴 수 있습니다.

댓글

GitHub 계정으로 로그인하시면 댓글과 질문을 남기실 수 있습니다. 남겨 주신 글은 이 저장소의 Discussions에 쌓입니다.

● main 214 posts UTF-8 LF © 2026 코징 RSS · GitHub