반응형

Mapping

  • Elasticsearch에서는 index에 document 형태로 데이터들을 정의한다. 
  • 이때, index(DB의 테이블에 해당)에 저장될 document(DB의 각 row에 해당)의 구조와 document 내의 field(DB의 테이블 칼럼에 해당)의 속성을 정의하는 설정을 mapping이라고 한다. 
  • DB의 DDL의 개념과 유사하다.
  • Mapping은 기본적으로 JSON 형식을 띤다. 
  • GET [index 이름]/_setting의 결과 중 mappings 부분을 통해 mapping 정보를 확인할 수 있다. 

 

동적 Mapping, 명시적 Mapping

  • Elasticsearch에서는 사용자가 정의하지 않은 mapping에 대해서 정보를 추론하여 자동으로 mapping해주는 동적 Mapping을 제공한다.
  • 예를 들어, DB에서는 정의되지 않은 칼럼에 Insert를 하는 경우 에러가 뜨지만, Elasticsearch에서는 데이터 값을 토대로 형추론을 하여, 새로운 Field가 만들어진다. 
  • 동적 mapping은 자동으로 지정해 줘서 편리하다는 장점이 있지만, mapping 정보 중 대다수가 처음 정의된 이후 변경이 불가능하기 때문에, 사용자가 직접 mapping 정보를 정의하는 명시적 mapping 방법을 사용하는 게 좋다.

Field

  • Elasticsearch에서 각 Field에 지정할 수 있는 타입은 아래와 같다. 
타입 종류 설명
숫자 타입 정수 - long : 64 비트 정수
- integer : 32 비트 정수
- short : 16 비트 정수
- byte : 8 비트 정수
POST /number_example/_doc { "price": 19.99 }
소수 - double : 64 비트 소수
- float : 32 비트 소수
- half_float : 16 비트 소수
date 타입 - format을 지정하여 시간대로 변환 가능
- 내부에는 long 숫자로 색인됨
POST /date_example/_doc { "event_date": "2023-12-31" }
배열 -별도 타입 지정은 필요없지만, 배열의 각 원소들이 동일한 타입을 가져야함 POST /array_example/_doc { "tags": ["elasticsearch", "mapping", "example"] }
object 타입 - Field 안에 하위 Field 를 저장함 
- 실제 저장할 때는, 평탄화시켜서 key-value 형태로 저장
- object 타입은 하위 Field 간 관계를 유지하지 않음
POST /object_example/_doc { "address": { "city": "Seoul", "postcode": 12345 } }
nested 타입 - 중첩된 배열 구조를 다룰 때, 요소 간의 관계를 유지하도록 설계된 데이터 타입
- object 타입과 달리, 하위 Field 간 관계가 유지된다.  
POST /nested_example/_doc { "reviews": [ { "user": "Alice", "rating": 5, "comment": "Great product!" }, { "user": "Bob", "rating": 4, "comment": "Pretty good." } ] }
text 타입 - elasticsearch의 핵심 기능인 텍스트 검색을 위해 사용되는 타입
- text 타입에 데이터를 넣으면, analyzer(기본 값 standard analyzer)를 거쳐, 데이- 터를 역색인하여 검색이 가능하도록 함.
POST /text_example/_doc { "description": "Elasticsearch is a powerful search engine." }
keyword 타입 - 정확한 값을 검색하거나, 집계, 정렬, 필터링 등에 사용되기 위해 사용하는 타입
- text 타입과 달리 analyzer를 거치지 않고, normalizer를 거친 결과를 저장(지정 안해주면 문장 그대로 저장)
POST /keyword_example/_doc
{
  "status": "ACTIVE"
}

 

※ object 타입과 nested 타입 비교

  • object 타입과 nested 타입은 기본적으로 Field 안에 하위 Field를 저장할 수 있다는 점에서 비슷하지만, 요소 간의 관계를 유지하느냐 유지하지 않느냐에 따라 각각 nested 타입과 object 타입으로 분류된다. 
  • 예를 들어, "person" : [{"name" : "minsu" , "age": 30}, {"name" : "bora" , "age": 29}]라는 데이터가 각각 object 타입과 nested 타입으로 저장되었을 때, elasticseach 검색 조건을 "name":"bora"면서, "age":30으로 찾았을 때, nested 타입에서는 실제 저장의도와 같게 검색이 되지 않지만, object 타입으로 저장하였을 때는 검색이 된다.
  • 이것은 object 타입이 하위 Field 간 관계를 유지하지 않고, 각 하위 Field의 원소들을 List 형태로 평탄화 시켜 저장하기 때문이다.
  • 따라서, 하위 Field에 대한 복수 조건이 많이 존재할 경우에는 nested 타입으로 저장해야한다. (상대적으로 무겁기 때문에 남용해서는 안된다.)

 

※ text 타입과 keyword 타입 비교

  • 예를 들어, "나는 밥을 먹었다"라는 문장을 각각 text 타입과 keyword 타입에 넣으면, text 타입은 "나는", "밥을", "먹었다"로 역색인되어 저장될 것이고(analyzer마다 다르겠지만), keyword 타입은 "나는 밥을 먹었다"로 문장 그대로 저장될 것이다. 
특성 text 타입 keyword 타입
저장된 값 Token(analyer의 결과) 전체 
검색 가능성 부분 단어 매칭, 전체 텍스트 검색 가능 정확하게 일치해야 검색 가능
검색 query match, match_phrase term, terms
집계/정렬 불가능(집계/정렬을 위하면 메모리 기반 fielddata 캐시 이용→ OOM 가능성 농후) 가능 (디스크 기반 doc_values 캐시 이용)
사용 사례 단어 검색 고정 데이터 ex) 도시명 등 특성 정보

 

 

_source Field

  • 문서를 Elasticsearch에 저장하는 요청이 왔을 때, Elasticsearch에서는 문서의 원본 JSON 문서를 저장하는 데, 이 메타데이터 필드를 _source Filed라고 한다. 
  • _source는 indexing 후에도 원본 상태(JSON 형태)를 유지하고, 쿼리 결과로 반환될 데이터를 제공한다.  예를 들어, "BaKe"라는 단어를 text 타입으로 저장하였을 때, "BAKE"로 anlyzer 처리 후 저장되겠지만, 실제 문서를 검색하면, "BaKe"라는 원본 상태로 조회된다.
  • _source Field가 없으면, 데이터 자체를 조회하는 것이 불가하다.
  • 만약, Indexing된 결과는 저장해야 하지만, 원본 문서를 디스크 용량상이나, 보안상(ex : 비밀번호 복호화된 것만 저장) 검색되지 원치 않는다면, _source에 저장되지 않도록 할 수 있다. (mapping - _source - enabled를 false로 PUT 호출)

 

'ElasticSearch' 카테고리의 다른 글

Elasticsearch (2) 주요 용어 & Lucene  (0) 2024.11.26
ElasticSearch (1) 기본 개념  (25) 2024.11.18
반응형

Elasticseach 주요 용어

  • Document : Elasticsearch가 저장하고 색인을 생성하는 JSON 형태의 데이터를 의미한다. 굳이 DB와 비교하면 Table의 각 row 개념이다.
  • Index : 비슷한 Document를 모아놓은 단위이다. DB에서 Table과 대응된다.
  • Shard : Index는 그 안의 document를 여러 shard로 분산 저장하여 고가용성을 보장한다. 원본 document는 primary shard에, 복제본은 replication shard에 저장된다.
  • _id : Index 내 document에 부여하는 고윳값이다. 사용자가 직접 정해줄 수 있고, 정하지 않으면 Elasticsearch에서 중복되지 않도록 알아서 생성한다. 굳이 DB와 비교하면 primary key 개념이다. 
  • Node : Elasticsarch process의 실행을 Node라고 한다. (일반적으로 서버에 1개 Elasticsearch process를 띄우기 때문에 1개 서버로 봐도 된다.) Node는 안에 여러 개의 shard를 가진다. 고가용성 보장을 위해, 같은 Node 안에 동일 shard의 primary 버전과 replication 버전을 두지 않는다. (죽으면 같이 죽어서 가용성 보장이 안되기 때문에) 
  • Cluster : Elasticsearch의 서비스를 제공하는 하나의 묶음이다. 일반적으로 여러개의 Node를 묶어 1개의 Cluster를 구성한다. Node는 Cluster 내에서 각 기능을 가진다. (이것은 Cluster 형태의 데이터 구조의 공통점이기도 하다.) 

 

Elasticseach과 Lucene

  • Elasticsearch는 Lucene을 기반으로 개발된 엔진이다.
  • Elasticsearch를 아주 간단히 정의하면 Lucene의 기능을 추상화하고 사용하기 편하도록 구성해 놓은 검색엔진이라고도 할 수 있을 정도로 Lucene은 Elasticsearch의 핵심 라이브러리이다. 
  • Elasticsearch에서 Lucence을 사용하는 방식은 다음과 같다.

[Lucene 동작]

1. Indexing

  • 사용자가 Document를 JSON 형식으로 Elasticsearch에 요청하면, Elasticsearch는 이를 Analyze 하여 Token을 생성한다. 
  • 이 과정에서 Elasticsearch는 Lucene의 Analyzer를 사용하여 텍스트를 분할하고, 이를 기반으로 Inverted Index를 생성한다. 

2. Flush 

  • Elasticsearch는 Lucence에서 만들어낸 Inverted Index를 바로바로 디스크에 저장하는 것이 아닌, memory 상에 저장하고 있다가 주기적으로 디스크에 Flush 하는 방식을 사용하여 Indexing 속도를 향상한다.
  • Flush는 RAM 버퍼 크기가 설정된 한도를 초과하였을 때나 특정 조건(document 수 초과)이 충족되었을 때, 명시적으로 호출(indexWriter.flush())했을 때 수행된다. 
  • Flush까지 수행된 데이터에 대해 검색이 가능하다. 
  • 여기서 용어를 주의해야 할 것은 Lucene의 Flush는 Elasticsearch에서 Refresh에 해당한다. (정확히 말하면 Elasticsearch Refresh 과정에서 Lucene의 Flush를 호출하는 것이다. Elasticsearch에서 Flush는 Lucene의 commit 과정을 포함한다.)

3. Commit

  • Flush가 디스크 상에 데이터를 기록하지만, 데이터 저장을 완전하게 보장하지 않는다. 이는 Flush가 디스크에 데이터를 임시로 기록했기 때문이다. 
  • Lucene은 주기적으로 fsync 시스템 콜을 통해, 페이지 캐시 내용과 디스크에 기록된 내용의 sync를 맞추는 작업을 수행한다.
  • Commit까지 완료되면, 시스템 종료가 일어나도 데이터가 완전하게 저장되었음을 보장한다. 
  • Lucene에서 Flush는 되었고, Commit 되지 않은 경우 시스템이 비정상 종료되거나, 내부 인덱스 구조의 재구성이 일어나는 경우 translog에 의해 복구되는데, translog에 기록이 남지 않는 경우에는 데이터가 유실된다.
  • 일반적으로 Commit은 개발자의 명시적 호출(IndexWriter.commit())로 일어난다. 

* Traslog

- 변경사항을 바로 디스크에 반영하면 속도 이슈가 있기 때문에, 각 shard 내에서 변경사항을 기록하는 translog를 기록한다. 강제 종료 시, shard 복구 작업에서 translog에 적힌 내용을 기반으로 데이터를 복구한다. 

 

 

4. Segment

  • Segment는 Lucenec이 데이터를 저장하는 가장 작은 단위의 Index 파일 묶음이다. 
  • Commit까지 완료되어 디스크에 기록된 파일들은 Segment 단위로 검색된다.
  • Segment는 불변의 데이터로 구성되어 있기 때문에, 새로운 document가 들어왔을 때는 새 segment가 생성되고, 기존 문서를 삭제하는 경우에는 실제 삭제를 하지 않고, Flag 표시만 해둔다. Update의 경우에는 삭제 Flag 처리를 해놓고, 새로운 Segment를 생성한다.
  • Segment 개수는 불변이기 때문에, 계속 쌓이는 상황이 발생한다. Lucene에서는 무한정 늘어나는 현상을 방지하기 위해, 중간중간에 Segment 병합을 수행한다. 이때, GC처럼 삭제 플래그 데이터를 삭제한다.

5. Lucene Index

  • 여러 segment들이 모여서 Lucene Index가 된다. 
  • Lucene은 이 Index 내에서만 검색이 가능하다.
  • Elasticsearch의 Index 개념은 Lucene의 Index 개념과 다른데, Lucene의 Index는 Elasticsearch에 Shard에 대응되고, Index 내에서 검색하였을 때, 각 shard(즉, Lucene의 Index)에서 각각 검색하여 나온 결과를 병합하여 결과를 만드는 구조이다. 이로 인해 분산처리가 가능하다.

 

 

 

'ElasticSearch' 카테고리의 다른 글

Elasticsearch (3) Mapping과 Field  (1) 2025.01.08
ElasticSearch (1) 기본 개념  (25) 2024.11.18
반응형

ElasticSearch

  • Elasticsearch는 2010년 Apache의 Lucene 라이브러리 기반으로 만들어진 분산 검색 엔진이다. 
  • Elasticsearch는 JSON 기반의 문서를 저장하고, 색인하여 검색할 수 있도록 한다.  
  • 데이터 시각화를 위한 도구인 Kibana와 데이터 수집 변환을 위한 Logstash, 경량 데이터 수집 플랫폼인 Beats와 함께 ELK 스택을 구성한다. 

ElasticSearch 특징

[검색 엔진]

  • Inverted Index : 검색엔진이기 때문에 키워드 검색을 위한 Inverted Index를 사용하여 빠른 검색 속도의 이점을 가진다. 이때, Analyzer를 검색 요구사항에 맞게 미리 지정하여 구성할 수 있어, 다양한 검색 조건에서 유용하게 사용될 수 있다.

→ Inverted Indexing이 Elasticsearch을 쓰는 가장 큰 이유인 것 같다. 또한, Analyzer 구성의 자유도가 매우 높기 때문에 최근 LLM model의 feature 등을 저장하는 RAG 모델 구성 등에 vector DB로 많이 사용되는 것 같다. 

 

[Cluster 구성]

  • 분산 처리 : Elasticsearch는 분산 처리를 지원한다. 일반적으로 검색 요청이 많은 시스템에서는 Elasticsearch를 여러 노드에 분산하여 성능 요구 사항을 맞춘다.
  • High Availability : Cluster 내 일부 노드의 장애에도 복제본 데이터를 통해 서비스 중단 없이 운영 가능하다. 
  • Scale out : Cluster 내 Node 수를 늘리고 싶을 때, Elasticsearch 설치만 하면, 데이터 복제 작업이 자동 수행된다.

DB 등에서 수평적 확장 시 H/W 단을 건들거나 Request 단을 바꿔야하는 귀찮음이 있는데 반해, Elasticsearch의 수평적 확장은 매우 간단했다. 

 

[Data]

  • REST API를 통한 작업 요청 : Elasticsearch는 JSON 형태로 문서를 저장한다. Elasticsearch에 작업 요청을 보낼 때도 JSON 기반의 REST API를 사용하기 때문에, Client 단에 별도의 setup이 필요하지 않다. (REST API 호출만 하면 됨)
  • Near Real-time Search : Elasticsearch는 데이터 Indexing 요청 후, 준실시간(1초 이내)의 검색이 가능하다. 
  • Tracsaction 지원이 안됨 : RBMS와 다르게 Transaction 개념이 없다.

Elasticsearch가 RDBMS와 가장 구분되는 특징인 것 같다. RDBMS에서는 데이터 정합성과 테이블 간 관계성이 매우 중요하고 엄격한데 반해, Elasticsearch는 Transaction 개념도 없고, 데이터 Join에 유리하지 않다. 실시간성 보장이 안되면서 Transaction을 지원하지 않기 때문에, 데이터 정합성이 매우 중요한 데이터등에는 적합하지 않다. (데이터 작업 중 연속해서 Request를 여러 번 날리면, Return값이 각기 다를 수 있음)

 

ElasticSearch 라이선스

  • Elasticsearch의 라이선스가 약간 복잡하고, 해석이 글마다 달라서 찾는 과정이 매우 복잡했다.
  • Elasticsearch는 최초 Apache 2.0 라이선스를 사용한 오픈소스로 시작했지만, 2021년 Elastic 라이센스와 SSPL을 도입한 현재 라이센스 체계로 변경되었다.
  • Elasticsearch의 라이선스는 크게 Elastic 라이센스와 SSPL로 구분된다.
    • Elastic 라이센스 : 개인 또는 기업이 내부적으로 Elasticsearch를 사용하는 것은 무료지만, 호스트형이나 관리형  형태로 상업적 사용은 제한된다. 여기서 상업적 사용 개념이 애매한데, 서비스에 읽기 전용 키바나 대시보드를 제공하거나, 서비스 내에서 검색 엔진으로 Elasticsearch를 제공하는 것은 문제가 되지 않으나, 사용자가 직접 API를 제어하는 형태로의 사용은 불가하다. (경계가 모호하다면 Elasticsearch에 직접 문의하는 것이 좋다.)
    • SSPL : Elasticsearch 소스코드를 이용한 파생 작업물을 서비스 형태로 제공하려면  파생 작업물 또한 SSPL 라이선스로 공개해야 한다. (이 부분은 AWS나 Google 같은 Cloud 업체에서 Elasticsearch에 자신들의 코드를 넣어 변현하여 서비스로 제공하여, Elasticsearch 구독에 악영향을 미치자 도입한 라이선스이다.)
  • 정리하자면, 기업단에서 Cloud 형태 등으로 Elasticsearch를 변형하여 서비스로 판매하지 않는 이상 큰 라이선스 이슈는 없다. 하지만, Elasticsearch에서 제공하는 더 폭 넓은 기능을 사용하기 위해서는 유료 구독하는 것이 좋고, 라이센스 이슈가 문제가 될 것 같을 때는 유료 구독하거나, Apache 라이선스를 따르는 7.10 이전 버전을 사용하는 것이 좋다. 

 

'ElasticSearch' 카테고리의 다른 글

Elasticsearch (3) Mapping과 Field  (1) 2025.01.08
Elasticsearch (2) 주요 용어 & Lucene  (0) 2024.11.26

+ Recent posts