ElasicSearch 소개
검색 엔진
- 엘라스틱서치는 루씬 기반의 오픈소스 검색 엔진이다.
- 단순한 텍스트 매칭 검색이 아닌 full-text-search가 가능하며 다양한 종류의 검색 쿼리를 지원한다.
- 다양한 애널라이저를 조합해 여러 비즈니스 요구사항에 맞는 색인을 구성할 수 있고 형태소 분석도 가능하다.
full-text-search란? (MongoDB 사이트 왈)
전체 텍스트 검색(full-text search)"은 전자적으로 저장된 방대한 텍스트 데이터에서 특정 텍스트를 검색하고, 쿼리에서 지정된 단어 중 일부 또는 전체가 포함된 결과를 반환하는 것을 의미합니다. 이에 비해 전통적인 검색은 정확한 일치만을 반환하는 것이 특징입니다.
분산 처리
- 엘라스틱 서치는 분산 처리를 고려하여 설계됐다.
- 데이터를 여러 노드에 분산 저장하며 검색이나 집계 작업 등을 수행할 때도 분산 처리를 지원한다.
고가용성 제공
- 클러스터를 구성하고 있는 일부 노드에 장애가 발생해도 복제본 데이터를 이용해 중단 없이 서비스를 지속할 수 있다.
- 이때 엘라스틱 서치는 다시 복제본을 만들어 복제본의 개수를 유지하면서 노드 간 데이터의 균형을 자동으로 맞춘다.
- 한대 이상의 노드로 클러스터를 구성해 높은 수준의 안전성을 달성하고 부하 분산이 가능하다
수평적 확장성
- 서비스에 요청 수나 데이터의 양이 증가하여 더 많은 처리 능력이 요구되는 때가 생긴다
- 엘라스틱 서치는 이런 상황에 대피해 수평적 확장을 지원한다.
- 더 많은 처리 능력이 필요할 때에는 새로운 노드에 엘라스틱서치를 설치하여 클러스터에 참여시키는 것만으로도 확장이 된다.
- 새 노드에 데이터를 복제하거나 옮기는 작업도 엘라스틱서치가 자동 수행한다.
JSON 기반의 REST API 제공
- 엘라스틱서치는 JSON 형태의 문서를 저장, 색인, 검색한다.
- 엘라스틱서치에 작업 요청을 보낼 때도 JSON 기반의 REST API를 사용한다.
- 특별한 클라이언트의 사전 설치 없이도 환경에 구애받지 않고 HTTP를 쉽게 이용할 수 있다.
준실시간 검색
- 엘라스틱 서치는 준실시간 검색을 지원한다.
- 데이터를 색인하자마자 조회하는 것은 가능하지만, 데이터 색인 직후의 검색 요청은 성공하지 못할 가능성이 높다.
- 엘라스틱서치가 역색인 을 구성하고 이 역색인으로부터 검색이 가능해지기까지 시간이 걸리기 때문이다.
- 대략 1초 정도 걸린다.
기타
- 데이터 색인 요청 후 200 OK를 받았다면 그 데이터는 확실히 디스크에 저장된다.
- 트랜잭션을 지원하지 않는다.
- 다양한 플로그인을 통한 기능 확장 지원
- 조인을 지원하지 않는다.
- 동적으로 스키마 생성이 가능하다.
클러스터
클러스터의 성능이 부족하면 노드를 늘려 대응할 수 있지만, 노드를 늘린다고 모두 성능을 늘릴 수 있는 것은 아니다.
기본 노드는 4가지가 있다.
- 마스터 노드: 클러스터 상태 관리 및 메타데이터 관리
- 데이터 노드: 문서 색인 및 검색 요청 처리
- 코디네이팅 노드: 검색 요청 처리
- 인제스트 노드: 색인되는 문서의 데이터 전처리
마스터 노드가 죽으면 마스터 후보 노드들 중에서 새로운 마스터가 된다.
클러스터는 어떤 노드에 어떤 요청을 해도 동일한 응답을 준다.
마스터 노드에 문서 조회 요청을 해도, 데이터 노드에게 해도 동일한 데이터를 준다.
클러스터에서 중요한 점은 각 노드들이 본연의 역할에 충실할수 있도록 구성해야 한다.
각 노드의 직접 접근을 차단하고 노드를 사용할 수 있는 API를 제공하는 것이 좋은 방법이다.
엘라스틱 구조
문서
엘라스틱서치가 저장하고 색인을 생성하는 JSON 문서를 뜻한다.
인덱스
- 문서를 모아 놓은 단위가 인덱스다. (문서가 저장되는 논리적 공간)
- 문서를 저장하기 위해서는 반드시 인덱스가 필요하다.
- 인덱스를 설계하는 것이 엘라스틱 서치를 사용하기 위해 고려해야하는 중요한 첫 단계
- 클라이언트는 이 인덱스 단위로 엘라스틱 서치에 검색을 요청한다.
- 인덱스의 설계에 따라 문서의 구조 및 검색 쿼리가 달라진다.
하나의 인덱스를 사용하면 관리해야 할 인덱스 수가 적어 관리 리소스가 적게 발생한다.
그러나 후에 쿼리와 문서의 구조가 복잡해질 수 있다.
여러 개의 인덱스로 나눈다면 각각의 경우에 최적화된 쿼리와 문서 구조를 사용할 수 있지만 관리 리소스가 많아진다.
인덱스는 하나의 인덱스로 단순하게 시작하고 사용 패턴에 따라 인덱스를 별도로 운영해야 한다.
샤드
- 인덱스에 색인되는 문서가 저장되는 공간이다.
- 하나의 인덱스는 반드시 하나 이상의 샤드를 가진다.
- 인덱스는 그 내용을 여러 샤드로 분리하여 분산 저장한다.
- 엘라스틱 서치는 고가용성을 제공하기 위해 샤드의 내용을 복제해둔다.
- 원본 역할을 담당하는 프라이머리 샤드, 복제본인 레플리카 샤드가 있다.
- 샤드는 인덱스를 생성할 때 설정한다.
프라이머리 샤드는 원본을 저장하며, 색인과 검색 성능에 모두 영향을 준다.
레플리카 샤드는 검색 성능에 영향을 주며, 프라이머리 샤드에 문제가 생기면 레플리카 샤드 중 한 개의 샤드가 프라이머리 샤드로 승격된다.
레플리카 샤드의 개수는 number_of_shards * number_of_replicas다.
총 샤드의 개수는 프라이머리 샤드 + 레플리카 샤드의 개수다.
예를 들어
number_of_shard가 5고 number_of_replicas가 2이면
레플리카 갯수는 10개고 프라이머리 샤드는 5개다. 그러므로 총 샤드의 갯수는 15개
샤드 라우팅
- 샤드가 3개가 있다고 생각하면, 문서들은 샤드 3개에 고르게 저장된다.
- 그래서 샤드의 개수가 바뀐다면 문서가 저장되는 규칙이 완전히 바뀌게 된다.
Routing Rule = 문서의 id % 샤드의 개수
따라서 인덱스를 생성할 때 프라이머리 샤드의 개수를 정하는 것은 매우 중요하다.
인덱스의 프라이머리 샤드는 인덱스를 만들고나면 변경이 불가능하기 때문이다.
기본 프라이머리 샤드의 값은 1인데, 이는 성능이 매우 안좋으므로 꼭 잘 설정해줘야 한다.
참고로 인덱스 템플릿을 통해 인덱스 생성 시의 샤드 개수를 설정가능하다.
인덱스 템플릿은 패턴을 적용할 수 있어서 편리하다.
매핑
- 매핑은 문서의 구조를 나타내는 정보다
- 엘라스틱 서치는 스키마리스가 아니라 미리 정의하지 않아도 될 뿐이다.
매핑 종류는 동적 매핑과 정적 매핑이 있다.
동적 매핑
- 처음 색인되는 문서를 바탕으로 매핑 정보를 엘라스틱 서치가 동적으로 생성한다.
- 어떤 문서가 색인될지 스키마를 미리 정의하지 않아도 된다.
- 동적 매핑에 의해 매핑 정보가 생성된 후에는 타입이 안맞을 경우 파싱 에러가 발생한다.
정적 매핑
- 문서의 매핑 정보를 미리 정의
- 어떤 문서가 색인될지 스키마를 미리 정의한다.
- 정적 매핑은 문서의 필드들이 가지는 값에 따라 타입을 지정해줄 필요가 있을 때 유용하다
- float 최대 값을 넘는 경우 반드시 double로 정적 매핑 필요하다.
- 불필요한 색인이 발생하지 않게 하기 위해 (ex 문자열 필드마다 자동 생성되는 keyword 타입)
_jd
인덱스 내 문서에 부여되는 고유한 구분자다. 인덱스 이름과 _id의 조합은 엘라스틱서치 클래스터 내에서 고유하다.
요청값에 _id를 지정해서 요청을 보낼 수 있다.
RDBMS와 비교
- ES index == RDBMS database
- ES mapping == RDBMS schema
- ES document == RDBMS row
- ES column == RDBMS field
ElasticSearch 동작과정
색인
문서를 분석하고 저장하는 과정을 색인이라고 한다.
색인 과정은 다음과 같다.
1. 인덱스가 있는가? 없으면 인덱스를 생성
2. 매핑 정보가 있는가? 매핑 정보가 없으면 동적 매핑
3. 매핑 정보가 올바른가? 올바르지 않다면 에러, 올바르다면 4번으로
4. inverted index 생성
5. 프라이머리 샤드에 저장
6. 레플리카 샤드에 복사
색인 과정은 적절한 수의 샤드 개수 설정에 큰 영향을 받는다.
성능에 문제가 있다면 샤드의 수를 늘리거나 데이터 노드를 스케일 아웃/업하면서 최적의 수치를 찾아간다.
만약 색인 성능에 문제가 있다면 클러스터로서의 이점을 살리고 있는지를 먼저 살펴봐야 한다.
Inverted Index란?
아래와 같은 데이터가 존재한다.
전통적인 RDBMS는 like 검색을 사용하기 때문에 데이터가 늘어날 수록 검색해야 할 대상이 늘어나 시간도 오래걸리고, 속도가 느리다.
엘라스틱 서치는 데이터를 저장할 때 다음과 같이 역 인덱스 (inverted index)라는 구조를 만든다.
역 인덱스는 책의 맨 뒤에 있는 주요 키워드에 대한 내용이 몇 페이지에 있는지 볼 수 있는 찾아보기 페이지에 비유할 수 있다.
엘라스틱서치에서는 추출된 각 키워드를 텀(term)이라고 부른다.
이렇게 역 이덱스가 있으면 fox를 포함하고 있는 도큐먼트들의 id를 바로 얻어올 수 있다.
엘라스틱서치는 데이터가 늘어나도 찾아가야 할 행이 늘어나는 것이 아니라 역 인덱스가 가리키는 id의 배열 값이 추가되는 것이므로 큰 속도의 저하 없이 빠른 속도로 검색이 가능하다.
이런 역 인덱스를 데이터가 저장된느 과정에서 만들기 때문에 엘라스틱서치는 데이터를 입력할 때 저장이 아닌 색인을 한다고 표현한다.
검색
검색 과정은 다음과 같다.
- 검색어 분석 == analyzer 적용
- inverted index 검색 == 생성된 토큰을 inverted index에서 검색
- 검색 결과 표시
Analyzer
- 문자열
- character filter
- tokenizer
- token filter
- tokens
문자열을 분석해서 inverted index 구성을 위한 토큰을 만들어내는 과정 (2번, 3번, 4번)을 애널라이저라고 한다.
검색 요청은 프라이머리 샤드와 레플리카 샤드 모두가 처리할 수 있다.
검색 성능에 문제가 있다면 클러스터로서의 이점을 살리고 있는지를 살펴봐야 한다.
Text vs Keyword
- text 타입은 Full-text-search를 위해 토큰을 생성된다.
- keyword 타입은 Exact Matching을 위해 토큰이 생성된다.
- keyword 타입이 색인 속도가 더 빠르다.
- 문자열 필드가 동적 매핑되면 text와 keyword 타입 두 개가 모두 생성된다.
- 문자열의 특성에 따라 text와 keyword를 정적 매핑해주면 성능에 도움이 된다.
- 예를 들어 이름은 text, 성별은 keyword 타입 등
참고자료
엘라스틱서치 바이블
https://www.inflearn.com/course/elasticsearch-essential/dashboard
https://esbook.kimjmin.net/06-text-analysis/6.1-indexing-data
댓글