text : 전문 검색(Full-text search)용. Analyzedkeyword : 정확한 값(Exact value)용. Not Analyzedlong, integer, short, byte, double, float, half_float, scaled_floatdate, date_nanosbooleanbinary (Base64 인코딩된 문자열)integer_range, float_range, long_range, double_range, date_range, ip_rangeobject: JSON 객체 (기본값)nested: 객체 배열을 독립적으로 쿼리해야 할 떄 사용 (내부적으로 별도 문서로 색인)geo_point (위도/경도), geo_shape (복잡한 지형)ip, completion (자동완성), token_count, percolatortext vs keyword의 결정적 차이이 두 타입의 차이는 데이터를 저장할 떄 분석기(Analyzer)를 거치느냐, 거치지 않느냐에 있다.
이 차이가 검색(Search), 정렬(Sorting), 집계(Aggregation)의 동작 방식을 완전히 바꾼다.
text 타입 (Full-Text Search)Standard Analyzer 기준, "Apple Pie"는 ["apple", "pie"]로 저장된다.fielddata를 켜야 하는데, 성능상 권장하지 않음)keyword 타입 (Exact Match)["Apple Pie"]라는 하나의 토큰으로 저장된다.apple로 검색하면 검색되지 않는다. 반드시 Apple Pie 전체가 일치해야 한다.가장 흔히 하는 실수는 keyword 필드에 대해 부분 검색을 시도하거나, text 필드에 대해 정확한 일치를 기대하는 것이다.
PUT /dev_index
{
"mappings": {
"properties": {
"product_desc": { "type": "text" }, // 분석됨
"product_category": { "type": "keyword" } // 분석 안 됨 (정확한 값)
}
}
}
POST /dev_index/_doc/1
{
"product_desc": "Super Fast Laptop",
"product_category": "Electronics"
}
| 쿼리 타입 | 대상 필드 | 검색어 | 결과 | 원인 |
|---|---|---|---|---|
| Match | product_desc | "laptop" | 성공 | Super, Fast, Latop 으로 토크나이징 되어있고 소문자 처리됨 |
| Term | product_desc | "Super Fast Laptop" | 실패 | 텀 쿼리는 정확한 토큰을 찾는데 역색인에는 쪼개진 단어들만 존재함 |
| Term | product_category | "Electronics" | 성공 | 저장된 값 Electronics와 정확히 일치 |
| Term | product_category | "electronics" | 실패 | keyword는 대소문자를 구분함 |
실무에서는 하나의 필들르 검색 용도와 정렬/집계 용도로 모두 사용해야 하는 경우가 많다
이 때 fields 속성을 사용한다
{
"mappings": {
"properties": {
"user_name": {
"type": "text", // 검색용 (analyzed)
"fields": {
"raw": {
"type": "keyword" // 정렬/집계용 (exact match)
}
}
}
}
}
}
user_name 필드 사용 (유사도 검색)user_name.raw 필드 사용 (정확한 값 기준)이미 정의된 필드의 타입은 변경할 수 없다
text로 토큰화되어 저장된 데이터를 나중에 keyword나 long으로 바꾸려면, 저장된 모든 데이터를 다시 읽어서 새로운 방식으로 저장 구조를 다시 짜야 한다._reindex API를 사용하여 기존 인덱스의 데이터를 마이그레이션 한다.