본문 바로가기

Dot Database/Elastic Search

Elasticsearch 검색 엔진 내부 동작과정: 클러스터링, RDBMS와 비교, 데이터 처리, 텍스트 분석

    Elasticsearch

    Elaistcsearch는 확장성이 뛰어난 Apache Lucene기반의 Java 오픈소스 분산 검색 및 분석 엔진이다. 

    • 분산 시스템이기 때문에 쉽게 스케일 아웃(Scale-out)이 가능하고 고가용성(HA)을 보장한다.

     

    Apache Lucene은 1999년 Doug Cutting에 의해 개발되었다. 

    • 풀텍스트 검색 엔진을 만들 수 있는 자바 라이브러리
    • 2005년 Apache Top Level 프로젝트로 선정
    • 루씬을 사용해 구현된 대표적인 검색엔진으로 Elasticsearch와 Solr 두 가지가 있다.
    • Elastic 사에는 10여 명의 루씬 커미터가 있으며 루씬의 60% 이상을 컨트리뷰션하고 있다.

     

    Elasticsearch 클러스터링 과정

    대용량 검색을 위해서는 클러스터링이 필요하다. Elasticsearch는 데이터를 샤드(Shard) 단위로 분리해서 저장한다. 하나의 샤드는 루씬 검색 쓰레드라고 부른다. 노드는 실행된 Elasticsearch의 단일 프로세스를 칭한다.

     

    Node

     

    1. 노드를 여러 개 실행시키면 같은 클러스터로 묶인다.

    노드 하나를 실행해서 저장하면 데이터가 샤드 단위로 분리되어 저장되었는데, 노드의 데이터가 점점 많이 차고있다고 하면 노드를 여러개 더 띄워서 한 클러스터로 묶을 수 있다. 가장 큰 시스템 단위가 클러스터(Cluster)이다.

     

    여러 개의 노드를 cluster로 묶기

     

    2. 샤드들은 각각의 노드들에 분배되어 저장된다. (Relocation)

    노드가 여러 개로 묶이게 되면 처음에 노드에 쌓여있던 데이터들이 다른 노드들로 새롭게 재배치된다.

     

    Relocation

     

    3. 무결성과 가용성을 위해 샤드의 복제본을 만든다. 

    Relocation이 되고난 샤드들은 복제본을 가지게 된다. 처음에 만들어진 샤드를 Primary라고 부르고 나중에 만들어진 샤드를 Replica라고 부른다. 디폴트로는 하나의 Replica를 만들어서 보통 한 쌍(Primary-Replica)의 구조를 갖고 있고 이 둘은 항상 같은 데이터 셋을 가지고 있다.  

     

    복제본 생성

     

    그리고 같은 내용의 복제본과 샤드는 서로 다른 노드에 저장된다. 만약 시스템 다운이나 네트워크 단절 등으로 유실된 노드가 생기면 다음 그림의 경우 다운된 노드에 존재하는 0, 4번 샤드가 불능이 된다. 하지만 다른 노드에 0, 4번 복제본이나 기존 샤드가 존재하기 때문에 해당 샤드로 대체가 가능하다.

     

    어떤 노드가 다운된 경우 다른 노드에 존재하는 샤드로 대체

     

    이 노드가 더이상 복구되지 않는다고 판단이 되면 Elasticsearch는 0, 4번 샤드를 자신이 아닌 다른 노드에 복제본을 만든다. 그렇게 노드의 수가 줄어도 샤드의 수는 변함없이 무결성을 유지할 수 있다.

     

    다른 노드에 복제본 생성

     

    Elasticsearch 검색 과정

    1. Query Phase

    데이터를 저장했을 때 사용자는 저장한 데이터가 어떠한 샤드에 들어갈 지에 대해 보통은 알 수 없다. (일부로 지정하는 방법이 있긴 하지만 권장되지 않는다.) 사실 어디에 들어가도 크게 상관없다. 왜냐하면 직접 검색을 하게 되면 검색 요청을 받은 노드는 검색 대상이 되는 모든 샤드들로 검색 명령을 전달한다.

     

    Query Phase

     

    그러면 각각의 샤드별로 그 검색을 수행하고 검색된 결과 큐를 노드로 리턴한다. 리턴된 결과는 루씬 doc id와 랭킹 점수만 가지고 있다.

     

    Query Phase

     

    2. Fetch Phase

    노드는 리턴된 결과를 랭킹 점수를 기반으로 정렬한 뒤 유효한 샤드들에게 최종 결과들을 다시 요청한다. 

     

    Fetch Phase

     

    그때 전체 문서 내용(_source) 등의 정보가 리턴되어 클라이언트로 전달된다.

     

    Fetch Phase

     

    Elasticsearch와 RDBMS 비교

    Elasticsearch는 풀텍스트(Full Text) 검색이 가능하다.

     

    RDBMS

    RDBMS 같은 경우 데이터를 테이블 형태로 저장한다. 여기서 인덱스를 만들 때 열을 기준으로 하나씩 만들게 된다. 검색을 하게되면 like 검색을 하게되어서 책의 맨 앞에 있는 제목 리스트와 같이 한줄 한줄씩 읽는 순차탐색을 진행하게 된다. 

     

    만약 rabbits을 검색한다면 1번부터 차례대로 검색하여 데이터를 찾는다.

     

    RDBMS의 index 구조

     

    Elasticsearch

    검색 엔진에서는 inverted index라는 구조로 RDBMS와는 정반대의 구조로 저장한다. 텍스트를 다 뜯어서 검색어 사전(Term)을 만든다. 책의 맨 뒤에 있는 페이지를 가리키는 키워드와 같다.

     

    검색 엔진의 inverted index 구조

     

    실제로는 이렇게 저장된다.

    실제로는 Elasticsearch는 풀텍스트를 저장하기 때문에 저장 방식이 위와 조금 다르다. 데이터를 저장할 때마다 데이터 처리 과정을 거치게 되는데 이러한 과정을 텍스트 분석(Text Analysis)라고 한다.

     

    데이터 저장 방식

     

    RDBMS vs 검색엔진

    이 둘은 서로의 목적이 다르기 때문에 데이터 저장 방식과 조회하는 과정 또한 차이가 난다.

    • RDBMS는 데이터가 중복되지 않게 정규화하여 저장하고 쿼리를 이용해서 검색한 결과를 만들어서(Join) 가져온다. 그래서 RDMBS 조회는 DB에 데이터 재료를 저장하여 해당 재료를 바탕으로 데이터를 만들어서 검색하는 것으로 보면 된다.
    • 검색엔진은 조회해서 나중에 볼 결과, 모양을 저장해놓고 그것들을 빠르게 가져올 수 있는 사전(역색인, inverted index)을 만들어 놓는 것이다. 
      RDBMS 검색엔진
    데이터 저장 방식 정규화 역정규화
    전문(Full Text) 검색 속도 느림 빠름
    의미 검색 불가능 가능
    Join 가능 불가능
    수정 / 삭제 빠름 느림

     

    Elasticsearch 텍스트 분석 과정

    1. 데이터 자르기 Tokenizing

    다음 두 문장을 저장한다고 할 때 Elasticsearch가 가장 먼저 하는 과정은 Tokenizing이다. 해당 과정은 데이터를 잘라준다. 그때 각 자른 데이터의 토큰들을 Term이라고 부른다. 보통은 Whitespace Tokenizer가 사용된다.

     

    Tokenizing

     

    2. 대소문자 변환하기 Token Filtering

    Tokenized된 Term들을 가공한다. 이 과정을 Token Filtering이라고 한다. 먼저 Lowercase Token Filter로 대소문자를 변환한다.

     

    대소문자 변환

     

    그 다음 토큰을 (보통 ascii 순서대로) 재정렬해준다.

    재정렬

     

    3. 불용어 제거하기 Stop Token Filter

    불용어(stopwords, 검색어로서의 가치가 없는 단어들)를 제거한다. a, an, are, at, be, but, by, do, for, i, no, the, to ... 등등 Stop Token Filter가 사용된다.

     

    가치없는 단어 제거

     

    4. 형태소 분석 후 변경하기 Snowball Token Filter

    형태소 분석 과정을 거친다. 보통 ~s, ~ing 등을 제거하는 과정이다. 보통 Snowball Token Filter를 사용한다. 한글은 의미 분석을 해야해서 좀 더 복잡하다.

    • jumping, jumps → jump
    • lazy  → lazi
    • rabbits  → rabbit

     

    ~s, ~ing 제거

     

    jumping, jumps → jump로 바뀌었으므로 토큰을 병합해준다.

     

    토큰 병합하기

     

    5. 동의어 처리하기 Synonym Token Filter

    경우에 따라서 Synonym Token Filter를 이용해 동의어 처리를 할 수 있다. fast랑 quick이라는 단어를 동의어 처리하게 되면 1번 document에는 quick이 있고 2번 document에는 fast가 있지만 quick이라고 검색을 했을 때도 fast라는 단어가 포함된 document도 같이 찾고 싶다고 할 때 이런 식으로 찾아낼 수 있다. 

     

    동의어 처리하기

     

    검색하는 과정에서 텍스트 처리

    검색어도 이와 같이 똑같이 텍스트 처리를 한다. "The lazy rabbits" 검색하면 다음 처리 과정이 이루어진다.

    • "The"는 불용어니 삭제한다
    • lazy → lazi로 변경한다
    • rabbits → rabbit으로 변경한다
    • 실제로 jumping이나 jumps로 jump로 검색한다.

     

    "The lazy rabbits" 검색

     


    참고

    Elastic Stack 제품 및 기능 소개

    데이터 분석 플랫폼의 새로운 트렌드 "엘라스틱서치"(엘라스틱서치코리아 김관호 상무)