7.2.2 숫자 - long, double ...

이 문서의 허가되지 않은 무단 복제나 배포 및 출판을 금지합니다. 본 문서의 내용 및 도표 등을 인용하고자 하는 경우 출처를 명시하고 김종민(kimjmin@gmail.com)에게 사용 내용을 알려주시기 바랍니다.

Elasticsearch는 자바에서 기본으로 사용되는 숫자 타입들을 지원합니다. 그리고 half_float, scaled_float 과 같이 Elasticsearch에서만 사용되는 타입들도 있습니다.

  • long : 64비트 정수 (-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807)

  • integer : 32비트 정수 (-2147483648 ~ 2147483647)

  • short : 16비트 정수 (-32768 ~ 32767)

  • byte : 8비트 정수 (-128 ~ 127)

  • double : 64비트 실수

  • float : 32비트 실수

  • half_float : 16비트 실수

  • scaled_float : 실수형이지만 부동소수점이 아니라 long 형태로 저장하고 옵션으로 소수점 위치를 지정합니다. 통화 (예: $19.99) 같이 소수점 자리가 고정된 값을 표시할 때 유용합니다.

모든 숫자 필드들에 공통적으로 설정 가능한 옵션들은 다음과 같은 것들이 있습니다.

  • "index", "doc_values", "boost" 옵션들은 text, keyword 필드의 옵션들과 동일합니다.

  • "coerce": <true | false> - 디폴트는 true 입니다. 숫자 필드들은 기본적으로 숫자로 이해될 수 있는 값들은 숫자로 변경해서 저장합니다. 예를 들어 integer 필드에 4, "4", 4.5 등을 입력하면 모두 자연수 4로 자동으로 변환되어 저장됩니다. false 로 설정하면 정확한 타입으로 입력되지 않으면 오류가 발생합니다.

  • "null_value" : <숫자값> - 필드값이 입력되지 않거나 null 인 경우 해당 필드의 디폴트 값을 지정합니다.

  • "ignore_malformed" : <true | false> - 디폴트는 false 입니다. 기본적으로 숫자 필드에 숫자가 아닌 문자나 불린 값이 들어오면 Elasticsearch는 오류를 리턴합니다. true로 설정하게 되면 숫자가 아닌 값이 들어와도 도큐먼트를 정상적으로 저장합니다. 하지만 해당 필드의 값은 _source 에만 저장되고 검색이나 집계에는 무시됩니다.

다음은 scaled_float 타입에서만 사용되는 옵션입니다.

  • "scaling_factor" : <10의 배수> - scaled_float 를 사용하려면 필수로 지정해야 하는 옵션입니다. 소수점 몇 자리까지 저장할지를 지정합니다. 12.3456 이라는 값을 저장하는 경우 scaling_factor: 10 으로 설정했으면 실제로는 12.3 이 저장됩니다. scaling_factor : 100 으로 설정했으면 12.34 가 저장됩니다.

"coerce": true 로 인해 "4.5" 가 integer 필드에 정상적으로 저장 되어도 _source 의 값은 그대로 "4.5" 입니다. 하지만 검색 또는 집계는 4로 적용됩니다. null_value 옵션도 마찬가지로 _source 에는 해당 필드가 null 또는 존재하지 않는 것으로 표시되지만 검색, 또는 집계에는 null_value에 해당하는 값으로 적용이 됩니다.

명심하세요. 전처리된 데이터가 아니면 항상 _source의 값은 변경되지 않습니다.

다음과 같이 my_number 인덱스에 number_val 필드를 byte 로 선언 한 뒤 도큐먼트들을 색인 해 보겠습니다. "coerce" 의 기본 값은 true 이지만 확실하게 하기 위해 이 옵션도 같이 지정하였습니다.

my_number 인덱스 선언
PUT my_number
{
"mappings": {
"properties": {
"number_val" : {
"type": "byte",
"coerce" : true
}
}
}
}
request
response
request
my_bumber 인덱스에 벌크로 도큐먼트 색인
PUT my_number/_bulk
{ "index" : { "_id": "1" }}
{ "number_val": 3 }
{ "index" : { "_id": "2" }}
{ "number_val": 4.5 }
{ "index" : { "_id": "3" }}
{ "number_val": "5.2" }
{ "index" : { "_id": "4" }}
{ "number_val": 1024 }
response
my_bumber 인덱스에 벌크로 도큐먼트 색인 결과
{
"took" : 46,
"errors" : true,
"items" : [
{
"index" : {
"_index" : "my_number",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 201
}
},
{
"index" : {
"_index" : "my_number",
"_type" : "_doc",
"_id" : "2",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1,
"status" : 201
}
},
{
"index" : {
"_index" : "my_number",
"_type" : "_doc",
"_id" : "3",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1,
"status" : 201
}
},
{
"index" : {
"_index" : "my_number",
"_type" : "_doc",
"_id" : "4",
"status" : 400,
"error" : {
"type" : "mapper_parsing_exception",
"reason" : "failed to parse field [number_val] of type [byte] in document with id '4'. Preview of field's value: '1024'",
"caused_by" : {
"type" : "illegal_argument_exception",
"reason" : "Value [1024] is out of range for a byte"
}
}
}
}
]
}

먼저 number_val 은 byte 이기 때문에 "_id": "4" 도큐먼트인 1024 값은 색인이 되지 않고 오류가 발생합니다. 이제 range 쿼리를 이용해서 3 보다 크거나 같고 4.2 보다 작은 값을 검색 해 봅니다.

request
response
request
3 이상, 4.2 미만인 값 검색
GET my_number/_search
{
"query": {
"range": {
"number_val": {
"gte": 3,
"lt": 4.2
}
}
}
}
response
3 이상, 4.2 미만인 값 검색 결과
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "my_number",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"number_val" : 3
}
},
{
"_index" : "my_number",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"number_val" : 4.5
}
}
]
}
}

분명 4.2 보다 작은 값을 검색했는데 결과에 4.5 값을 가진 "_id": "2" 도큐먼트가 같이 검색이 되었습니다. _source 에는 4.5 로 값이 들어가 있지만 number_val 필드는 byte 이기 때문에 실제로는 4.5 가 아닌 4 가 저장이 되어 있습니다. 따라서 4.2 보다 작은 값으로 검색이 됩니다. 같은 이유로 _source 에는 텍스트 "5.2" 가 있는 "_id": "3" 도큐먼트 역시 실제로는 자연수 5 가 저장이 됩니다.

조금 전 살펴 본 이유로 숫자 필드를 동적으로 생성하는 것은 매우 위험합니다. 다량의 데이터가 색인 될 때 만약에 가장 처음 들어 온 도큐먼트의 숫자 값이 4 와 같은 자연수인 경우 필드는 자동으로 long 타입으로 생성이 됩니다. 이후에 정수가 아닌 5.5 같은 소수점을 포함한 실수가 들어와도 오류가 발생되지 않고 정상적으로 도큐먼트가 저장됩니다. 하지만 실제로는 5.5 가 아닌 정수 5 가 저장되기 때문에 나중에 검색이나 집계에 오류가 발생하게 됩니다.