📚FOS Study
홈카테고리
홈카테고리
📚FOS Study

개발 학습 기록을 정리하는 블로그입니다.

바로가기

  • 홈
  • 카테고리

소셜

  • GitHub
  • Source Repository

© 2025 FOS Study. Built with Next.js & Tailwind CSS

목록으로 돌아가기
🗄️database/ opensearch

Mapping

약 4분
GitHub에서 보기

Mapping

  • OpenSearch의 데이터 타입은 인덱스의 Mapping을 통해 결정 됨
    • 데이터가 어떻게 저장되고 검색될지 결정하는 핵심 요소

1. OpenSearch의 주요 데이터 타입

  • String Types:
    • text : 전문 검색(Full-text search)용. Analyzed
    • keyword : 정확한 값(Exact value)용. Not Analyzed
  • Numeric Types:
    • long, integer, short, byte, double, float, half_float, scaled_float
  • Date Types:
    • date, date_nanos
  • Boolean:
    • boolean
  • Binary:
    • binary (Base64 인코딩된 문자열)
  • Range Types:
    • integer_range, float_range, long_range, double_range, date_range, ip_range
  • Complex Types:
    • object: JSON 객체 (기본값)
    • nested: 객체 배열을 독립적으로 쿼리해야 할 떄 사용 (내부적으로 별도 문서로 색인)
  • Geo Types:
    • geo_point (위도/경도), geo_shape (복잡한 지형)
  • Specialised Types:
    • ip, completion (자동완성), token_count, percolator

2. text vs keyword의 결정적 차이

이 두 타입의 차이는 데이터를 저장할 떄 분석기(Analyzer)를 거치느냐, 거치지 않느냐에 있다.
이 차이가 검색(Search), 정렬(Sorting), 집계(Aggregation)의 동작 방식을 완전히 바꾼다.

text 타입 (Full-Text Search)

  • 동작 원리:
    • 데이터 저장 시 Analyzer를 통과한다.
    • 문장을 토큰 단위로 쪼개고, 소문자로 변환하거나 불용어를 제거하는 등의 정제 과정을 거쳐 **역색인(Inverted Index)**을 생성한다.
  • 용도:
    • 본문 검색, 이메일 내요으, 제품 설명 등 긴 텍스트의 내용을 검색할 떄
  • 특징:
    • Standard Analyzer 기준, "Apple Pie"는 ["apple", "pie"]로 저장된다.
    • 대소문자 구분 없이 검색 가능 하다 (일반적인 설정 시)
    • 주의: 기본적으로 정렬이나 집계에 사용할 수 없다. (메모리를 많이 소모하는 fielddata를 켜야 하는데, 성능상 권장하지 않음)

keyword 타입 (Exact Match)

  • 동작 원리:
    • 데이터를 들어온 그대로(Verbatim) 단일 토큰으로 저장한다.
    • 분석기를 거치지 않는다
  • 용도:
    • ID, 이메일 주소, 상태 코드, 태그ㅜ, 카테고리 등 정확한 일치가 필요한 필드
  • 특징:
    • "Apple Pie"는 ["Apple Pie"]라는 하나의 토큰으로 저장된다.
    • apple로 검색하면 검색되지 않는다. 반드시 Apple Pie 전체가 일치해야 한다.
    • Doc Values라는 열 지향(Columnar) 저장소 구조를 사용하여 정렬과 집계에 최적화 되어있다.

3. 비교 예시 및 검증

가장 흔히 하는 실수는 keyword 필드에 대해 부분 검색을 시도하거나, text 필드에 대해 정확한 일치를 기대하는 것이다.

(1) 인덱스 매핑 생성

PUT /dev_index
{
  "mappings": {
    "properties": {
      "product_desc": { "type": "text" },      // 분석됨
      "product_category": { "type": "keyword" } // 분석 안 됨 (정확한 값)
    }
  }
}

(2) 데이터 삽입

POST /dev_index/_doc/1
{
  "product_desc": "Super Fast Laptop",
  "product_category": "Electronics"
}

(3) 검색 결과 차이

쿼리 타입대상 필드검색어결과원인
Matchproduct_desc"laptop"성공Super, Fast, Latop 으로 토크나이징 되어있고 소문자 처리됨
Termproduct_desc"Super Fast Laptop"실패텀 쿼리는 정확한 토큰을 찾는데 역색인에는 쪼개진 단어들만 존재함
Termproduct_category"Electronics"성공저장된 값 Electronics와 정확히 일치
Termproduct_category"electronics"실패keyword는 대소문자를 구분함

4. 실무 팁: Multi-fields (멀티 필드)

실무에서는 하나의 필들르 검색 용도와 정렬/집계 용도로 모두 사용해야 하는 경우가 많다
이 때 fields 속성을 사용한다

{
  "mappings": {
    "properties": {
      "user_name": {
        "type": "text", // 검색용 (analyzed)
        "fields": {
          "raw": {
            "type": "keyword" // 정렬/집계용 (exact match)
          }
        }
      }
    }
  }
}
  • 검색 시 : user_name 필드 사용 (유사도 검색)
  • 정렬/집계 시 : user_name.raw 필드 사용 (정확한 값 기준)

궁금한 점

Mappings를 변경도 가능한가? : "사실상 불가능"

이미 정의된 필드의 타입은 변경할 수 없다

  • 이유: OpenSearch(Lucene)의 역색인(Inverted Index) 구조는 불변이다.
    • 이미 text로 토큰화되어 저장된 데이터를 나중에 keyword나 long으로 바꾸려면, 저장된 모든 데이터를 다시 읽어서 새로운 방식으로 저장 구조를 다시 짜야 한다.
  • 가능한 경우:
    • 새로운 필드를 추가하는 것은 가능하다
  • 해결책: Reindexing (재색인)
    • 올바른 매핑을 가진 **새로운 인덱스(v2)**를 생성한다.
    • _reindex API를 사용하여 기존 인덱스의 데이터를 마이그레이션 한다.
    • **Alias(별칭)**을 사용하여 애플리케이션의 중단 없이 포인터를 v1에서 v2로 스위칭한다.
database 카테고리의 다른 글 보기수정 제안하기
목차
  • Mapping
  • 1. OpenSearch의 주요 데이터 타입
  • 2. `text` vs `keyword`의 결정적 차이
  • `text` 타입 (Full-Text Search)
  • `keyword` 타입 (Exact Match)
  • 3. 비교 예시 및 검증
  • (1) 인덱스 매핑 생성
  • (2) 데이터 삽입
  • (3) 검색 결과 차이
  • 4. 실무 팁: Multi-fields (멀티 필드)
  • 궁금한 점
  • Mappings를 변경도 가능한가? : "사실상 불가능"