TL;DR
- 인덱스 설계에 신경써야 하는 이유
- 설정에 따라 동작과 특성이 매우 달라진다.
- 인덱스 설정은 직접해야한다. 문서 생성으로 자동x
3.1 인덱스 설정
인덱스 확인
GET my_index/_settings
3.1.1 number_of_shards
- 이 인덱스가 데이터를 몇 개의 샤드로 쪼갤 것인지 지정하는 값
- 주의
- 한 번 지정하면 reindex 같은 동작을 통해 인덱스를 통쨰로 재색인하는 등 특별한 작업을 수행하지 않는 한 바꿀 수 없다.
- 클러스터에 샤드 숫자가 너무 많아지면 클러스터 성능이 떨어진다.
- 운영
- 엘라스틱서치 7부터 1로 변경됨, 미만까지는 5였음
- 오버샤딩하는 경향을 확인해 기본값을 수정한 것
- 다만 실제 운영 환경에서 데이털르 담기 시작하면 반드시 이 값을 적절한 값으로 조정해야한다.
- 엘라스틱서치 7부터 1로 변경됨, 미만까지는 5였음
3.1.2 number_of_replicas
- 주 샤드 하나당 복제본 샤드를 몇 개 둘 것인지를 지정하는 설정이다.
- 어느 정도의 고가용성을 제공할 것인지 등을 고려해서 지정하면 된다.
PUT [인덱스 이름]/_settings
{
“index.number_of_replicas” : 0
}
- 0
- 복제본 샤드 생성하지 않는다.
- 대용량의 초기 데이터를 마이그레이션하는 등의 상황에 쓰기 성능을 위해 주로 사용한다.
3.1.3 refresh_interval
- 인덱스를 대상으로 refresh를 얼마나 자주 수행할 것인지를 지정
- refresh
- 인덱스에 색인된 문서는 refresh 되어야 검색 대상이 된다.
- 즉 검색 반영 주기
{
“index.refresh_interval” : “1s”
“index.refresh_interval” : null
}
- default (null)
- 명시적으로 설정하지 않으면 기본적으로 1초
- 1s
- 1초에 한번,
- -1s
- 주기적 refresh 수행
- 30초 이상 검색 쿼리가 들어오지 않는 것을 확인하면 검색 쿼리 들어올 때까지 refresh 수행하지 않음.
- index.search.idel.after
- 그 시간
3.1.4 인덱스 설정을 지정하여 인덱스 생성
- 인덱스(토픽) 없이 문서를 만들면 모두 기본값이 지정된다.
- 실제 환경에서는 적절하지 않다.
인덱스 생성
PUT my_index2
Response
{
"acknowledged": true, // 해당 인덱스가 클러스터에 제대로 생성되었는지 여부
"shards_acknowledged": true, //
"index": "my_index2" //
}
- acknowledged
- 타임아웃 전에 클러스터에 제대로 생성되었는지 여부
- false 라고 실패한 건 아님
- 정확히는 타임아웃 전에 상태가 업데이트 완료되었는지
- 타임아웃 전에 클러스터에 제대로 생성되었는지 여부
- shards_acknowledged
- 타임아웃 전에 지정한 개수만큼 샤드가 활성화 됐는지
- false 라고 실패한 건 아님
- wait_for_active_shards
- 인덱스 생성 시 설정
- 기본적으로는 1개의 샤드
- 타임아웃 전에 지정한 개수만큼 샤드가 활성화 됐는지
3.2 매핑과 필드 타입
- ES 인덱스에 매핑된 필드가 아닌 문서를 생성할 경우 ES는 적당한 필드 타입을 지정해서 매핑 정보를 생성한다
3.2.1 동적 매핑(Dynamic mapping) vs 명시적 매핑(Explicit Mapping)
심플 타입
text
keyword
date
long
double
boolean
ip
숫자 타입
long
- 64bit, signed
integer
- 32bit signed
short
- 16bit signed
byte
- 8bit signed
double
- 64bit floating point
float
- 32bit floating point
half_float
- 16bit floating point
작은 비트를 사용하면?
- 색인과 검색 시 이득이 있다.
- 저장할 때는 실제 값에 맞춰 최적화되어서 디스크 사용량에는 이득이 없다.
배열
- 배열을 표현하는 별도의 타입 구분이 없다.
계층 구조를 지원하는 타입
Object 타입
- JSON 문서는 필드의 하위에 다른 필드를 여러 포함하는 객체 데이터를 담을 수 있다.
Nested 타입을 사용해야 하는 이유
{
"spec": [
{
"cores": 12,
"memory": 128,
"storage": 8000
},
{
"cores": 1,
"memory": 4,
"storage": 2000
}
]
}
->
{
"spec,cores": [12, 1]
"spec.memory": [128, 4]
"spec.storage": [8000, 2000]
}
- 동적 매핑으로 배열 만드는 경우 모든 배열에 있는 값이 평탄화되어 평기 때문에 적절한 검색이 불가능하다.
Nested 타입
- Object 와 다르게 배열 내 각 개체를 독립적으로 취급한다
{
"mappings": {
"properties": {
"spec": {
"type": "nested",
"properties": {
"cores": {
"type": "long"
},
"memory": {
"type": "long"
},
"storage": {
"type": "long"
}
}
}
}
}
}
- nested는 일반 search 로 검색 불가하다
- nested는 배열 각 객체를 내부적으로 별도의 루씬 문서로 분리해 저장한다 원소 100개 → 문서까지 101개를 내부적으로 생성
GET nested_test/_search
{
"query":{
"bool": {
"must": [
{
"term": {
"spec.cores": "12"
}
}
]
}
}
}
GET nested_test/_search
{
"query":{
"nested": {
"path": "spec",
"query":{
"bool": {
"must": [
{
"term": {
"spec.cores": "12"
}
}
]
}
}
}
}
}
Text타입과 Keyword 타입
Text
- 애널라이즈가 적용된 후 색인된다.
- 들어온 문자열 그대로 역색인 구성하지 않고 토크나이저 후 역색인 구성
- 토큰에 필터를 적용 후(후처리) 최종적으로 역색인에 들어가는 형태를 텀(term)이라고 한다.
Keyword
- 토큰을 쪼개지 않고 역색인 구성
- 애널라이저 대신 노말라이저 적용
- 간단한 전처리만을 거친 뒤 커다란 단일 텀으로 역색인을 구성한다.
PUT /keyword
{
"mappings": {
"properties": {
"keywordString": {
"type": "keyword"
},
"textString": {
"type": "text"
}
}
},
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
}
}
- match는 text타입인 경우 검색 질의어도 애널라이저로 분석 → hello, world 로 쪼개서 검색
3.2.3 doc_values
- 개념
- 인덱스된 문서 필드의 데이터를 디스크에 정렬된 방식으로 저장하는 기능을 말합니다. 이러한 저장 방식은 검색, 정렬, 집계 및 스크립팅 작업을 빠르고 효율적으로 수행할 수 있게 해줍니다.
- 디스크를 기반으로 한 자료 구조로 파일 시스템 캐시를 통해 효율적으로 정렬, 집계, 스크립트 작업을 수행할 수 있도록 설계됐다.
- 특징
- text, annotated_text 타입 제외 모든 필드 타입이 doc_values 지원
- doc_values 지원하는 필드의 경우 기본값을 true다
- 도입 이유
- 원래 필드의 원본 데이터를 _source 필드에 저장하고, 이 데이터를 기반으로 다양한 검색과 질의를 처리합니다. 그러나 **_source**에서 직접 데이터를 읽어서 처리하는 것은 CPU와 메모리 사용량이 많고, 처리 속도가 느릴 수 있습니다. **doc_values**는 이 문제를 해결하기 위해 도입되었습니다.
- 장점
- **doc_values**는 필드의 데이터를 역색인과 별개로 디스크에 컬럼 기반의 포맷으로 저장합니다. 이 구조 덕분에 Elasticsearch는 필터링, 정렬, 집계 등의 작업을 할 때 필요한 필드 데이터만 효율적으로 액세스할 수 있습니다. 특히 대량의 데이터를 다루는 집계 작업에서 **doc_values**는 메모리 사용량을 크게 줄이면서도 빠른 처리 속도를 가능하게 합니다.
3.2.4 fielddata
- text타입은 파일 시스템 기반 캐시인 doc_values 사용 불가, 대신 fielddata라는 캐시를 사용
- 동작
- 정렬, 집계 등 작업 시에 역색인 전체를 힙 메모리에 올린다.
- 특징
- OOM 발생시킬 수 있어 주의해야하며, 기본적으로 비활성화이다.
- 활성화하는 건 매우 신중해야 한다
- 이미 분석된 내용을 이용해 집계 등을 수행하기 때문에 의도와 다른 결과가 나올 수 있기 때문
3.2.5 _source
- 문서 색인 시점에 전달된 원본 JSON 문서를 저장하는 메타데이터 필드
- _source 자체는 역색인 생성하지 않아 검색 대상이 아니다.
- 비활성화
- JSON 문서를 통째로 담기 때문에 디스크를 많이 사용한다.
- 주의
- 업데이트와 update_by_query API 사용 불가
- 문서는 기존 문서 삭제, 수정하는 것이 아니라 새 문서를 색인하는 작업
- 즉 기존 문서를 확인후에 필요한 문서만 색인하는데 _source 가 없기 때문
- reindex API 사용 불가
- reindex
- 원본 인덱스에서 내용을 대상 인덱스에 새로 색인하는 작업
- 사용
- 매핑, 샤드 개수 등 동적으로 변경하기 어려운 내용을 운영상의 이슈로 바꿔야만 할 때 사용
- 버전 올릴 때 reindex 수행해 예전 버전 인덱스 재생성해야 하기 때문에 그냥 필수
- 결론
- 운영과 데이터 관리에 있어 핵심 API 임으로 웬만하면 비활성화하지 말자
- reindex
- 업데이트와 update_by_query API 사용 불가
인덱스 코덱 변경(_source 비활성화 대신)
- 다른 성능을 희생하더라도 디스크 공간을 절약해야만 하는 상황 → 압축률을 높여라
- 기본값
- IZ4
- best_compression
- DEFLATE
PUT codec_test
{
"settings": {
"index": {
"codec": "best_compression"
}
}
}
Synthetic source
- 인조, 합성 soruce 의미로서 JSON 원문을 저장하지 않는다.
- 특징
- 다소 작업 성능이 떨어진다. → 즉 _source 조회가 많이 필요 없는 작업 위주면 성능 향상을 기대해볼 수 있다.
- _source 비활성화와는 다르게 reindex 작업도 가능하다.
- 제약
- 모든 필드가 Docvalues 를 사용하는 필드여야한다.
- 동작
- 필드 이름이나 배열 내의 값을 오름차순 재정렬,
- 문자, 필드 이름은 최대한 Object 계층 구조로 조립하려 하는 등 차이를 발생
- 대신 인덱스 크기가 매우 줄어든다.
3.2.6 index
- index 속성은 해당 필드의 역색인 만들 것인지 지정
- 색인 성능
- 기본값
- true
- false 이면?
- 역색인이 없어 일반적인 검색 대상x
- 8.1 이상부터는 index 속성을 false 로 검색 대상 제외되지 않음
- → doc_values 이용해 검색 수행 가능
- → doc_values 검색은 설계된 자료형이 아니라 검색 성능은 떨어짐
- → 디스크 공간 절약하고 색인 성능 얻는 것
- 8.1 이상부터는 index 속성을 false 로 검색 대상 제외되지 않음
- 역색인 생성이 x일 뿐 doc_values 사용하는 타입 필드면 집계 대상으로 사용 가능
- 역색인이 없어 일반적인 검색 대상x
PUT mapping_text/_mapping
{
"properties": {
"notsearchableText": {
"type": "text",
"index": false
},
"docValuesSearchableText": {
"type": "keyword",
"index": false
}
}
}
- index가 없고, doc_values 사용하지 않으면 검색 시 에러가 난다.
{
"error": {
"root_cause": [
{
"type": "query_shard_exception",
"reason": "failed to create query: Cannot search on field [notsearchableText] since it is not indexed.",
"index_uuid": "X4OUTAz2TeqOc8aiHhWUUQ",
"index": "index_test"
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "index_test",
"node": "O4dwMILzQSGaP0o8MZkEIw",
"reason": {
"type": "query_shard_exception",
"reason": "failed to create query: Cannot search on field [notsearchableText] since it is not indexed.",
"index_uuid": "X4OUTAz2TeqOc8aiHhWUUQ",
"index": "index_test",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Cannot search on field [notsearchableText] since it is not indexed."
}
}
}
]
},
"status": 400
}
3.2.7 enabled
- 특징
- object 타입 필드에만 적용
- false
- 파싱조차 수행하지 않는다.
- _source 에는 저장되지만 다른 어느 곳에도 저장되지 않는다.
- 역색인 생성하지 않기 때문에 검색도 불가능하다.
- 정렬이나 집계의 대상도 될수 없다.
'DataOps > Elasticsearch' 카테고리의 다른 글
[Elasticsearch] 8. 엘라스틱서치의 내부 동작 상세 (0) | 2024.04.03 |
---|---|
[Elasticsearch] 3. 인덱스 설계 (Template, Routing) (0) | 2024.03.13 |
[Elasticsearch] 3. 인덱스 설계 (Analyzer, Tokenizer) (0) | 2024.03.13 |
[Elasticsearch] 2. 엘라스틱서치 기본 동작과 구조 (0) | 2024.01.26 |
[Elasticsearch] 1. 엘라스틱 서치란? (0) | 2024.01.26 |
댓글