Elasticsearch 문자 정렬
사이드 프로젝트를 진행하며, 기존 날짜 타입 필드가 아닌 문자 필드를 정렬 할 일이 생겼습니다.
예를 들어 Y-m-d 형식의 date 타입인 필드를 정렬하고자 합니다.
{
"mapping": {
"properties": {
"date": {
"type": "date"
}
}
}
}
그렇다면 아래의 쿼리로 쉽게 정렬할 수 있습니다.
{
"query": {
"match_all": {}
},
"sort": [
{
"date": {
"order": "asc"
}
}
]
}
하지만, 문자 타입의 필드를 정렬하고자 한다면..
가상으로 nameEN
의 필드를 가진 인덱스를 생성하고, nameEN
필드를 정렬하고자 합니다.
{
"mapping": {
"properties": {
"nameEN": {
"type": "text"
}
}
}
}
우리는 nameEN
의 첫 글자를 기준으로 정렬하고자 합니다.
A-Z 순서로 정렬하고자 한다면, 아래와 같이 쿼리를 작성할 수 있습니다.
{
"query": {
"match_all": {}
},
"sort": [
{
"nameEN": {
"order": "asc"
}
}
]
}
하지만, ES 에서는 오류를 반환합니다.
{
"type": "illegal_argument_exception",
"reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [nameEN] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory."
}
그 이유는, text 타입의 필드는 기본적으로 fielddata
옵션이 비활성화 되어 있기 때문입니다.
fielddata
란 역색인된 인덱스를 메모리에 로드하여 검색을 빠르게 하는 기능입니다.
fielddata
를 활성화 하면, 메모리를 많이 사용하게 되므로, text 타입의 필드를 정렬할 때는 다른 방법을 사용해야 합니다.
그 방법은 간단하게 해결 가능합니다.
바로 keyword
타입으로 맵핑하는 것입니다.
{
"mapping": {
"properties": {
"nameEN": {
"type": "keyword"
}
}
}
}
keyword
타입은 fielddata
가 아닌 doc_values
를 사용합니다.
doc_values
는 역색인된 인덱스를 디스크에 저장하는 방식입니다.
그리고, 쿼리를 아래와 같이 작성하면 정상적으로 정렬이 됩니다.
{
"query": {
"match_all": {}
},
"sort": [
{
"nameEN": {
"order": "asc"
}
}
]
}
하지만 우리가 원하는 검색을 하기 위해서는 keyword
로만은 부족합니다.
여러 analyzer 도 붙여 검색을 하고자 한다면, text
타입으로 맵핑해야 합니다.
그럼.. text
타입과 keyword
타입을 동시에 사용하는 방법은 없을까 ..
다중 필드 (multi fields)
바로 다중 필드 (multi fields) 를 사용하여 맵핑을 설정하면 됩니다.
{
"mapping": {
"properties": {
"nameEN": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
아래와 같이 다중 필드를 이용해 여러개의 analyzer 를 사용할 수도 있습니다.
{
"mapping": {
"properties": {
"nameEN": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
},
"ngram": {
"type": "text",
"analyzer": "ngram_analyzer"
}
}
}
}
}
}
이렇게 검색은 text
타입으로 하고, 정렬은 keyword
타입으로 할 수 있습니다.
{
"query": {
"match_all": {}
},
"sort": [
{
"nameEN.keyword": {
"order": "asc"
}
}
]
}