부정거래 탐지데이터 적발에서 데이터 조건이 너무 많고 다양한 사유로 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, ...]
Markdown
복사
kafka & spring 검색시 Posting List의 5번을 노출해줌으로서 매우 빠르고 속도 또한 O(1)에 가깝습니다.
만약 MySQL기준으로 조회를 한다면 WHERE content LIKE '%kafka%’ 와 같은 형태가 될 것이며, 이렇게 될 시 B-tree index를 사용하지 못하여 풀스캔 발동 될 것입니다.
2.
색인 시점의 분석(Analysis)
•
“미리 해두는 것”
"Kafka를 사용한 Spring Boot 애플리케이션"
→ character filter (HTML 제거 등)
→ tokenizer (형태소 분석 / standard / nori 등)
→ token filter (소문자화, 불용어 제거, 어간 추출, 동의어)
→ [kafka, 사용, spring, boot, 애플리케이션]
Markdown
복사
위와 같은 문장을 저장할때 미리 해당하는 Analysis를 사용하여 변환하여 저장해 놓습니다.
대소문자 무시, 어미 변형("running" → "run"), 동의어("노트북" = "랩탑") 처리가 전부 검색 시점이 아니라 색인 시점에 완료합니다.
역색인으로 인한 장점
1.
Term dictionary 탐색이 O(log n) 이하
•
term들이 사전순 정렬되어 있고, Lucene은 여기에 FST(Finite State Transducer)를 씁니다.
term들이 사전순 정렬되어 있다? 라는 의미는
term들이 사전순 정렬 → FST로 접두사 공유 → 메모리에 올릴 수 있음 → 디스크 seek 없이 오프셋 획득 역인덱스에 저장된 단어들이 가 → 강아지 → 고양이 → 나무 순으로 줄 세워져 있다는 뜻입니다.
왜 굳이 정렬해 두냐면, 정렬돼 있어야 "안 보고 건너뛰기"가 가능하기 때문입니다. 사전에서 "고양이"를 찾을 때 1페이지부터 넘기지 않죠. 중간을 펴서 "나"가 나오면 "아, 뒤쪽은 안 봐도 되겠다"하고 앞쪽만 봅니다. 정렬이 안 돼 있으면 이 판단 자체가 불가능해서 전부 다 봐야 합니다.
추가적으로 디스크 seek 없이 오프셋을 획득한다는 것은 아래 3번째 의미인 메모리 힙에 올려둘수 있다라는 것.
2.
FST는 공통 접두사를 공유하는 상태 기계
•
사전 본문(= 실제 단어 목록과 뜻)은 두껍고 무겁습니다. 그래서 맨 뒤에 붙은 얇은 색인 페이지를 따로 만듭니다.
ㄱ ..... 3쪽
ㄴ ..... 88쪽
ㄷ ..... 140쪽
Plain Text
복사
FST가 바로 이 색인 페이지 역할입니다. 그런데 그냥 목록이 아니라, 압축돼 있습니다.
강아지, 강물, 강당 세 단어를 저장할 때 강을 세 번 쓰지 않고 한 번만 쓰고 셋이 나눠 씁니다. 아파트 현관문 하나를 여러 집이 공유하듯이요. 단어가 많아질수록 겹치는 부분도 많아지니, 절약되는 양이 눈덩이처럼 커집니다.
3.
메모리 사용량이 작아서 힙에 올려둘 수 있다.
•
색인 페이지가 압축 덕분에 아주 얇아졌으니, 메모리에 올릴수 있습니다.

