매핑
- 관계형 데이터베이스에서 스키마와 비슷한 개념
- RDBMS에서 스키마는 테이블을 구성하는 구성요소 간의 논리적인 관계와 정의
- Elasticsearch에서는 JSON 형태의 데이터를 Apache Lucene이 이해할 수 있도록 바꿔주는 작업
- Elasticsearch가 검색 엔진으로 전문 검색과 대용량 데이터를 빠르게 실시간 검색할 수 있는 이유는 매핑이 있기 때문인데 매핑을 엘라스틱 서치가 자동으로 하면 동적 매핑, 사용자가 직접 설정하면 정적 매핑 혹은 명시적 매핑
- Elasticsearch의 인덱스에 들어가는 데이터의 타입을 정의하며 인덱스에 추가되는 데이터의 유형을 결정
- 매핑을 지정하지 않아도 동적으로 매핑이 생성되지만 실무에서는 미리 저장할 필드들을 파악하고 정적 매핑 하는 것을 권장
- 인덱스 및 데이터 유형을 정의하기 위해서는 정적 매핑 사용
동적 매핑과 정적 매핑
1. 동적 매핑
- 문서를 색인할 때 필드명과 유형을 구성할 필요 없고 Elasticsearch에서 자체적으로 타입을 추론하여 매핑
- 문서 색인 시 신규 필드가 유입되면 동적 매핑을 사용하여 필드의 데이터 유형을 결정하고 신규 필드 추가
- 동적 매핑 규칙을 동적필드 매핑 또는 동적 템플릿을 사용하여 구성해 기존 매핑을 사용자 지정할 수 있음
- 새로운 필드 생성 시 문서를 색인하고 동적으로 필드를 생성할지 결정하는 파라미터 설정 가능
- 필드 타입이 잘 못 정의되어 검색 시 오류를 일으킬 가능성이 있음 (ex 날짜 타입)
- 실제로 정합성 및 검색 품질 높이기 위해 인덱스 생성 시 혹은 데이터 변경 시 정적 매핑 추천
1.1 동적 매핑 세팅 - dynamic 파라미터
옵션 | 설명 |
true | default 옵션으로 새로운 필드를 매핑에 생성 |
runtime | 새로운 필드를 매핑에 런타임 필드로 추가 필드가 추가는 되지만 색인되지 않고 _source 쿼리 시 로드 됨 |
false | 새로운 필드는 무시되고 매피에 추가되지 않음 색인되거나 검색할 수는 없지만, _source로 변환된 필드에는 표시 됨 |
strict | 새로운 필드가 감지되면 예외가 발생하고 문서가 색인되지 않음 매핑에 명시적으로 새로운 필드르 추가해야 됨 |
1.1.1 파라미터가 strict인 경우 예시
부연 설명
- 새로운 필드 감지 시 아래와 같이 예외가 발생함
1.2 동적 매핑 기준
원본 소스 데이터 타입 | 동적 매핑으로 변환된 데이터 타입 |
null | 필드 추가 X |
boolean | boolean |
float | float |
integer | long |
object | object |
string | string 데이터 형태에 따라 1. date 2. text/keword 멀티 필드 |
동적 매핑 시 주의할 점
- 개발 단계에서 스키마 설계를 고민하기보다 데이터의 형태만 고민하면 되므로 무척 편하지만
- 숫자 타입은 무조건 범위가 가장 넓은 long으로 매핑되어 불필요한 메모리를 차지하여 데이터가 많을 경우 성능 저하를 유발할 수 있음
- 문자열의 경우 검색과 정렬 등을 고려한 매핑이 제대로 되지 않을 수 있음
2. 정적/명시적 매핑
- 문서에 저장할 데이터의 종류를 미리 알고 있어 인덱스를 생성할 때 필드와 유형을 직접 정의
- 인덱스를 생성할 때 mappings 정의를 설정하거나 mapping API를 이용해 매핑을 지정할 수 있음
- 인덱스 생성 시 mappings.properties 아래에 필드명과 필드 타입을 지정해 주면 됨
- 정의된 필드를 삭제하거나 데이터 필드 유형을 실시간으로 변경하는 것은 불가능
- 필드명을 변경하거나 데이터 타입을 변경하기 위해서는 새로운 인덱스를 만들거나 reindex API를 이용해야 하므로 매핑 작업은 신중하게 하는 것을 권장
* properties 파라미터 외엥도 analyzer나 format 등을 설정하는 파라미터도 있으므로 공식 문서 참조하는 것을 권장
3. 매핑 타입
- 명시적 매핑을 위해서는 Elasticsearch에서 사용하는 데이터 타입에 대한 이해가 요구됨
- 좋은 스키마가 관계형 데이터베이스의 성능을 끌어올리는 것처럼 매핑을 잘 활용하면 Elasticsearch의 인덱스 성능을 올릴 수 있음
데이터 형태 | 데이터 타입 | 설명 |
텍스트 | text | 전문 검색이 필요한 데이터로 텍스트 분석기가 텍스트를 작은 단위로 분리 |
keyword | 정렬이나 집계에 사용되는 텍스트 데이터로 분석을 하지 않고 원문을 통째로 색인 | |
날짜 | date | 날짜/시간 데이터 |
정수 | byte, short, integer, long |
byte: 부호 있는 8비트 데이터 short: 부호 있는 16비트 데이터 integer: 부호 있는 32비트 데이터 long: 부호 있는 64비트 데이터 |
실수 | scaled_float, half_float, double, float |
scaled_float: float 데이터에 특정 값을 곱해서 정수형으로 바꾼 데이터, 정확도는 떨어지나 필요에 따라 집계 등에서 효율적으로 사용 가능 half_float: 16비트 부동소수점 실수 데이터 float: 32비트 부동소수점 실수 데이터 double: 64비트 부동소수점 실수 데이터 |
불린 | boolean | 참/거짓 데이터로 true/false만을 값으로 가짐 |
IP 주소 | ip | ipv4, ipv6 타입 IP 주소를 입력할 수 있음 |
위치 정보 | geo_point, geo_shape |
geo_point: 위도, 경도 값을 가짐 geo_shape: 하나의 위치 포인트가 아닌 임의의 지형 |
범위 값 | integer_range, long_range, float_range, double_range, ip_range, date_range |
범위를 설정할 수 있는 데이터 integer_range, long_range는 정수형 범위 float_range, double_range는 실수형 범위 ip_range는 IP 주소 범위 date_range는 날짜/시간 데이터 범위 값을 저장하고 검색할 수 있게 함 최솟값과 최댓값을 통해 범위를 입력 |
객체형 | object | 계층 구조를 갖는 형태로 필드 안에 다른 필드들이 들어갈 수 있음 |
배열형 | nested | 배열형 객체를 저장 객체를 따로 색인하여 객체가 하나로 합쳐지는 것을 막고, 배열 내부의 객체에 쿼리로 접근 가능 |
join | 부모(parent)/자식(child) 관계를 표현할 수 있음 |
4. 다양한 필드 타입 유형
4.1 keyword 필드 타입 유형
- 검색 시 aggregations, term level query, sorting 항목에서 사용
- analyzer를 사용하지 않고 원문 데이터를 그대로 색인
- 입력된 문자를 하나의 토큰으로 저장
- 검색 시 입력된 문자와 동일한 문자가 입력되어야 검색됨
- 공백, 대소문자 등을 구분하지 않기 때문에 서로 다른 키워드로 인식되어 정확하게 질의
- keyword, constant_keyword, wildcard 타입으로 설정
- 주로 다음과 같은 항목에 사용됨
- 이메일
- 태그
- 카테고리
- 정렬이 필요한 항목
- 집계(aggregations)가 되어야 하는 항목
4.1.1 keyword 필드 타입의 주요 매개변수
매개변수 | 설명 |
normalizer | analyzer와 비슷한 역할이지만 형태소 분석을 수행하지 않음 색인되는 문자열의 전처리 ex) cafe, Cafe, Cafè 모두 같은 "cafe"로 색인되게 하기 위해서는 lowercase filter를 사용하는 normalizer 정의 |
doc_values | 정렬, 집계 등을 하기 위해 on-disk data 구조로 열 기반 저장소에 저장할지를 결정 |
boost | 필드 가중치를 부여하며 가중치에 따라 유사도 점수가 달라짐 검색 시 결과나 순위에 영향을 끼침 |
field | 동일한 문자열로 여러 번 색인을 수행할 수 있도록 하위 필드를 정의 같은 문자에 다른 분석기 사용 |
null_value | null 값일 때 대체할 단어를 결정 |
4.1.2 constant_keyword 필드 타입
- 색인 시 모든 문서가 동일한 값을 색인
- 필터링 속도를 높이는데 사용
부연 설명
- 모든 문서에서 sale_status가 항상 "sale"
- 같은 값을 반복해서 저장할 필요가 없으므로, 저장 공간과 메모리를 절약
- 모든 문서에서 동일한 값을 가지기 때문에 검색 속도가 매우 빠름
4.1.3 wildcard 필드 타입
- 내부적으로 wildcard 필드는 n-gram을 적용하여 전체 필드 값을 색인하고 전체 문자열 저장
- 검색 속도는 느림
- 구조화 되지 않은 컨텐츠가 포함된 필드를 keyword 필드에 매핑
- wildcard, regexp 쿼리에서 사용되며 *, ?와 같은 형태로 사용
4.2 text 필드 타입 유형
- analyzer의 분석 프로세스를 통해 전체 텍스트를 개별 단어로 만들어 검색
- analyzer를 사용하여 토큰을 분리 한 후 저장
- ex) 볼보XC60 -> [볼보, XC60]
- 분해된 단어만 입력해도 관련 있는 문서 검색이 가능
- 별도의 analyzer를 지정하지 않을 경우 standard analyzer가 분석기로 지정됨
- 한글 형태소 분석기를 사용하기 위해 검색에 사용할 분석기를 별도로 인덱스 settings에 지정 가능
- 색인에 사용할 분석기와 검색에 사용할 분석기를 별도로 지정 가능
4.2.1 text 필드 타입의 주요 매개변수
매개변수 | 설명 |
analyzer | 색인 시 사용할 분석기 지정 search_analyzer를 지정하지 않을 경우 같은 분석기로 구성 analyzer를 지정하지 않을 경우 standard analyzer 사용 |
search_analyzer | 검색 시 사용할 분석기를 지정하는 매개변수이며 analyzer와 같은 분석기 사용 가능 보통은 동의어 등의 구성 때문에 다른 분석기로 사용 |
fielddata | text 필드를 집계 또는 정렬을 사용할 수 있게 설정 dynamic 설정으로 매핑을 업데이트하여 변경 가능 true로 설정 시 메모리 사용량이 많기 때문에 keyword 타입을 field 파라미터로 생성하여 사용하는 것을 권장 |
4.2.2 match_only_text 필드 타입
- 로그 분석 시 사용하는 text 필드
- 일반 text 필드에 비해 디스크 공간을 10% 절약
- keyword 필드와 text 필드의 중간 단계
- 전체 텍스트 쿼리를 실행하지만 결과에 관련 score 값을 생성하지 않아 빠름
- standard analyzer에서만 사용 가능
4.2.3 search_as_you_type 필드 타입
- n-gram 분석기를 사용하여 전방 일치 혹은 중간 일치를 할 수 있게 하는 데이터 타입
- 매핑에 구성한대로 분석/분석기가 구성되지 않을 경우 standard analyzer 사용
4.3 멀티 필드 유형
- Elasticsearch 5.x 버전부터 string 타입이 text와 keyword라는 두 가지 타입으로 분리됨
- string 타입을 동적 매핑하면 멀티 필드가 적용되어 두 타입 모두 생성됨
- 공간을 절약하고 쓰기 속도를 높이기 위해 색인 전 매핑을 설정하는 것이 유리
- 단일 필드 입력에 대해 여러 하위 필드를 정의하는 기능으로 이를 위해 fields라는 매핑 파라미터가 사용됨
- fields는 하나의 필드를 여러 용도로 사용할 수 있게 만들어줌
- 문자열의 경우 전문 검색이 필요하면서 정렬도 필요한 경우도 있음
- 또한 처음 데이터 스키마를 잡는 시점에서는 키워드 타입으로 충분히 처리가 가능한 범주형 데이터였지만 데이터가 늘어나면서 전문 검색이 필요해지는 경우도 생김
- 위와 같은 케이스들에서는 text와 keyword를 동시에 지원해야 함
4.4 array 필드 타입 유형
- Elasticsearch에 별도의 배열 타입이 존재하지 않음
- 배열로 생성된 값은 동일한 타입을 가져야 하며 기본적으로 모든 데이터는 배열로 문서를 생성할 수 있음
- ex) [-1, 1]
- ex) [{id: 1}, {id: 2}, {id: 3}]
- ex) ["볼보", "XC60"]
4.5 numeric 필드 타입 유형
- 자바에서 사용하는 숫자형 데이터 타입을 지원
- 작은 수의 타입을 사용해야 색인 및 검색을 효율적으로 수행
- 동적 매핑 적용 시 모든 필드를 수용할 수 있도록 큰 타입으로 지정되어 메모리 낭비 유발할 수 있음 (long, double)
4.6 date 필드 타입 유형
- 내부적으로 Date 타입은 UTC로 변환되며 내부적으로는 UTC의 밀리초로 변환되어 저장
- JSON에서 date 타입은 문자열로 표현됨
- 매핑 설정 시 문자열 format을 명시해야 함
- default format: "yyyy-MM-ddTHH:mm:ssZ"
- 여러 개의 포맷을 동시에 매핑 설정 가능
- ex) "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
4.7 range 필드 타입 유형
- 검색 시 relation 필드를 사용
- 범위의 연속된 데이터를 저장
- 시작과 끝 값만 지정
- ex) 게시물의 게시 기간
- ex) 허용 IP 범위
- ex) 가격 필터
4.8 geo_spatial 필드 타입 유형
- 위/경도 등 위치 정보를 담은 데이터를 저장
- ex) 반경 내 쿼리
- ex) 위치 기반 집계
- ex) 위치 별 정렬 등 작업
- ex) 지리적으로 중심점으로부터 거리 별 문서 집계 및 정렬
4.8.1 geo 필드 타입 유형
- geo 필드 타입을 설정할 경우 동적 매핑이 되지 않음
- 위도와 경도를 사용하여 geo_point 필드 타입을 정의
- geo_shape 필드는 하나의 위치 포인트가 아닌 임의의 지형
4.9 Object 필드 타입 유형
- JSON 포맷은 내부 객체를 계층으로 표현
- 내부적으로는 flat한 형태로 key-value 쌍으로 변경하여 저장
4.10 Nested 필드 타입 유형
- Object 필드 타입의 특화 버전
- Object Array를 저장하기 위해 사용
- 배열로 Object를 저장하면 각각의 Object는 독립성을 유지
- 저장된 각각의 Object 별 문서 조회 가능
- nested query를 사용하여 검색어 질의
4.10.1 Object vs Nested 필드 타입 유형
- Object 필드도 array 형태로 저장 가능하지만 문서의 개별성을 보장하는가의 차이가 존재
- Object 필드에 대해서는 korean-name: "닷지", english_name: "hyundai"로 질의해도 결과 반환
- 반면 Nested 필드에 대해서는 korean-name: "닷지", english_name: "hyundai"로 질의하면 결과 반환 X
- korean_name: "닷지", english_name: "durango"가 한 쌍
- korean_name: "현대", english_name: "hyundai"가 한 쌍
- Nested 필드는 각각의 Object를 독립적으로 저장하기 때문에 key-value 쌍이 맞아야 결과 반환
4.11 dense vector 필드 타입 유형
- float 형태의 value로 저장됨
- script score 쿼리 혹은 KNN search API를 사용하여 유사한 벡터를 검색할 때 사용
- HNSW 알고리즘을 사용하여 KNN 검색 지원
- ex) 이미지 검색의 유사도 측정
- KNN으로 vector 색인 시 색인되는 시간이 오래 걸릴 수 있음
4.11.1 dense vector 필드 타입 매개변수
매개변수 | 설명 |
type | KNN 알고리즘 유형 (HNSW만 지원) |
m | hnsw 그래프에서 각 노드가 연결된 근접 이웃 수 기본값은 16으로 숫자가 클 수록 색인 속도가 느려지지만 정확도는 상승 |
ef_construction | 최근접 이웃의 목록을 조합하는데 추적할 후보 수 기본값은 100, 숫자가 클 수록 검색 속도가 느려지지만 정확도는 상승 |
dims | 벡터 차원수 2048을 초과할 수 없음 |
index | 필드를 검색 할 지에 대한 여부 |
similarity | KNN에서 사용할 vector 유사도 메트릭 (l2_norm, dot_product, cosine) 사용 가능 |
인덱스 alias 정의
- 인덱스명을 대체할 인덱스명으로 사용할 수 있음
- 여러 인덱스를 연결하여 하나의 인덱스처럼 사용할 수 있음
- 신규 인덱스에 색인하고 alias를 사용하여 다운타임 없이 인덱스 교체 가능
- _alias API를 사용하여 인덱스에 세팅
1. 인덱스 alias 추가/조회
- PUT [인덱스]/_alias/[새로운 alias명]
- 인덱스에 alias를 추가하거나 삭제를 간단하게 하는 기능
- alias를 조회 시 매핑되어 있는 인덱스를 확인 가능
2. 인덱스 alias 삭제
- DELETE [인덱스]/_alias/[삭제할 alias명]
DELETE car-master.static.alias/_alias/car-master-reader
3. 인덱스 alias 한번에 추가 및 삭제
- POST _aliases
- 무중단으로 인덱스를 변경하기 위해 한번에 인덱스 alias를 추가하고 삭제
4. 인덱스 라이프 사이클
- 인덱스를 mapping과 setting 정보와 함께 생성
- 신규 인덱스에 write alias를 연결
- write alias에 데이터 색인
- read alias를 신규 인덱스로 변경 후 기존 인덱스 삭제 혹은 close api를 통해 비활성화
인덱스 템플릿
- 매번 같은 패턴으로 생성되는 인덱스를 정의하기 위해 매핑과 세팅을 정의하지 않고 자동으로 인덱스 구성
- template을 지정할 경우 옵션에 따라 우선순위를 정의할 수 있음
- 자동으로 생성되는 인덱스 및 실시간으로 데이터를 저장하는 로그성 데이터의 인덱스 생성 시 용이
- 템플릿은 인덱스명과 템플릿에 정의된 인덱스 조건의 이름이 맞으면 정의된 구성으로 인덱스 생성
- 사용자 정의 구성으로 인덱스를 생성할 수 있음
- mappings: 필드의 스키마 정의
- settings: 샤드의 크기 등 인덱스와 관련된 세팅 정의
- aliases: 인덱스 생성 시 인덱스의 별칭 지정
1. 템플릿 유형
1.1 index 템플릿
- _index_template API를 사용
- 정적으로 인덱스에 대한 템플릿을 구성하고 인덱스 패턴에 따라 인덱스의 정보를 저장
부연 설명
- "index_patterns": ["car-master.*"]는 이 템플릿이 적용될 인덱스의 이름 패턴을 지정하며 car-master.* 패턴을 가진 모든 인덱스가 해당
- "priority": 1은 이 템플릿의 우선 순위를 나타내며 여러 템플릿이 동일한 인덱스 패턴에 적용될 수 있는 경우, 우선순위가 높은 템플릿이 우선 적용됨
- template 섹션은 템플릿이 적용될 때 사용할 구체적인 설정과 매핑을 정의
1.2 component 템플릿
- _component_template API 사용
- 필요한 구성을 정의하고 자체적으로 재사용 가능한 템플릿
- 하나 이상의 템플릿과 연결 될 수 있음
- 인덱스 템플릿은 인덱스 별로 묶이기 때문에 같은 이름의 필드 구성 요소를 재사용할 수 없음
- 인덱스 템플릿으로 정의된 인덱스와 유사한 인덱스 생성 시 전체 템플릿을 다시 생성해야 함
부연 설명
- "index_patterns": ["car-sub.*"]는 이 템플릿이 적용될 인덱스의 이름 패턴을 지정하며 car-sub.* 패턴을 가진 모든 인덱스가 해당됨
- "priority": 0은 이 템플릿의 우선 순위를 나타내며 우선순위가 낮을수록 다른 템플릿에 의해 덮어 쓰일 가능성이 높음
- 이 템플릿의 우선 순위는 0이므로 기본값으로 낮은 우선순위를 가짐
- "composed_of": ["settings-template", "mapping-template", "aliases-template"]는 이 템플릿이 구성 요소 템플릿으로부터 설정, 매핑, 별칭을 가져와서 조합한다는 것을 나타냄
2. 다이내믹 템플릿
- 매핑을 동적으로 지정하는 템플릿 기술
- 로그 시스템이나 비정형화된 데이터처럼 필드 타입을 정확히 정의하기 힘들고, 필드 개수를 정할 수 없는 경우 유용한 템플릿
- 다이내믹 템플릿은 이처럼 매핑을 정확하게 정할 수 없거나 대략적인 데이터 구조만 알고 있을 때 사용할 수 있는 방법
부연 설명
- my_string_fields는 임의로 정의한 다이내믹 템플릿명이며 다이내믹 템플릿명 밑으로 2개의 설정 존재
- match_mapping_type은 조건문 혹은 매핑 트리거이며 여기서는 문자열 타입 데이터가 있으면 조건이 만족되어 트리거링 됨
- mapping은 실제 매핑을 적용하는 부분이며 문자열 타입의 데이터가 들어오면 keyword 타입으로 매핑
부연 설명
- name 필드는 문자열 타입이기 때문에 다이나믹 템플릿에서 설정한 대로 keyword 타입으로 매핑
- age 필드는 numeric 타입이기 때문에 long 타입으로 동적 매핑
3. 템플릿 삭제
- DELETE _index_template/[템플릿명]
참고
- 패스트 캠퍼스 - 고성능 검색 엔진 구축으로 한 번에 끝내는 Elasticsearch
- 엘라스틱 개발부터 운영까지 (김준영, 정상운 저)
'Elastic Search' 카테고리의 다른 글
[Elasticsearch] 검색 (0) | 2024.06.07 |
---|---|
[Elasticsearch] 분석기(analyzer) (3) | 2024.06.07 |
[Elasticsearch] 데이터 모델링 기초 (0) | 2024.06.06 |
[Elasticsearch] 개념과 용어 정리 (1) | 2024.06.02 |
[Elasticsearch] 설정 관련 정리 (0) | 2022.11.16 |