데이터 타입 변환에 대해 알아보기 전에 먼저 이 거 한번 봐주세요.

 

다음 중 정수 5는?

1. "5"

2. 오

3. 5.0

4. 5

 

정답은 4입니다. 그럼 오답풀이를 해볼까요?

1번은 문자 5

2번도 그냥 문자 5

3번은 부동소수점 5.0

 

5.000001이나 5.0이나 5나 사실 그냥 5는 5인데... 자료형이 앞에 붙으면 int 5 랑 float 5.0은 느낌이 너무 다르네요.

 

엘라스틱서치는 데이터 타입을 정해진 규칙에 따라서 변환을 해줘요. 예를 들면, 정수형 데이터만 받기로 한 number_one이라는 필드에 문자열 값 "5"가 들어오면 이 건 사실 에러가 나야 하는 건데 엘라스틱서치에서는 coercion이라는 기능을 통해서 문자열 "5"를 정수로 바꿀 수 있는지 확인하고 바꿀 수 있다면 정수로 바꿔서 넣어줘요. 부동 소수 5.0도 마찬가지로 정수형으로 변환이 가능하면 정수형으로 변환해서 넣어줘요. 그런데 보기 2번과 같이 리터럴 하게 '오', "오", "five", 'FIVE' 이런 건 못 바꿔줘요. 아니 안 바꿔줘요. 이 거 바꿔주면 아마 더 머리에서 쥐가 날 꺼 같아요. '사만 참천이 십육'. 이런 거. 바꿔준다고 하면 큰일 날 거 같아요. 문제가 생기면 찾기 너무 힘들 거 같아서요.

 

인덱스의 매핑을 확인해서 어떤 필드에 어떤 데이터 타입을 넣을지 볼 수 있는 건 이미 알아요. 그럼 간단하게 인덱스에 몇몇 타입의 데이터를 넣어보고 어떻게 동작하는지, 이 coercion 기능을 끄는 건 어떻게 끄는지, 끄면 어떻게 동작하는지 알아보아요.

...
"number_one": {
        "type": "integer"
      },
      "number_two": {
        "type": "integer",
        "coerce": false
      }
...

먼저 매핑을 만들어주는 요청에서 볼 거는 coerce라는 매핑 파라미터를 명시적으로 false라고 알려주지 않으면 기본적으로는 true인가 보다.라는 걸 알 수 있어요. 다음.

POST /data_coercion/_doc/1
{
  "number_one": "10"
}

큰따옴표로 묶은 문자열 데이터 타입이라도 coerce 옵션이 (default로) true이기 때문에 정수로 변환되어서 저장되었을 것 같아요. 왜냐하면 에러가 안 났으니까요. 그럼 확인을 해볼게요.

"_source" : {
    "number_one" : "10"
  }

음? number_one에 문자열로 들어가 있네?

 

10초만 생각해보세요.

 

 

 

 

_source에는 인덱싱 할 당시의 모습 그대로 들어가고 엘라스틱서치 내부에서는 변환해서 저장된다고 했어요.

그럼 어떻게 확인해볼 수 있을까요? 만약 문자열이라면 집계나 정렬에 사용할 수 없을 거예요.

POST /data_coercion/_search
{
  "query": {
    "range": {
      "number_one": {
        "gte": 9
}}}}

number_one에서 9보다 크거나 같은 값을 찾아주세요.

했더니 _doc/1이 나왔어요. 10보다 크거나 같은 걸 찾아주세요 해도 나왔어요. 11보다 크거나 같은 걸 찾아달라 하니 없대요.

확실히 정수형으로 저장되었나 봐요. 정렬도 되는 거 보면. 그럼 이제 coerce를 false로 설정해 놓은 number_two에 한 번 값을 넣어볼게요.

POST /data_coercion/_doc/2
{
  "number_two": "10"
}


POST /data_coercion/_doc/2
{
  "number_two": 10
}

첫 번째 요청은 에러가 날 거고, 두 번째 요청은 정상적으로 값이 들어갈 거예요.

이렇게 해서 엘라스틱서치에서 강제적으로 형 변환이 어떻게 이루어지는지 확인해봤어요.

 

데이터 타입을 정수형으로 정의하고 문자열 안에 들어간 정수가 형 변환이 되는지 봤어요.

그럼 10.1은 어떻게 들어갈까요? 9.9는?

float으로 정의해 놓은 필드에 정수를 넣으면 어떻게 들어갈까요?

 

매핑을 수정해서 float형 필드를 하나 더 넣어볼게요.

PUT /data_coercion/_mapping
{
  "properties": {
    "num_float": {
      "type": "float"
    }
  }
}

여기에 정수도 넣어보고 문자열로도 넣어보면 되겠네요.

 

그런데 이렇게 알아서 바꿔줘서 들어가는 것도 때로는 편하고 좋을 때도 있지만 때로는 불편할 때도 있어요. 그럴 때는 "coerce": false를 사용하면 좋을 거 같아요.

 

https://www.elastic.co/guide/en/elasticsearch/reference/7.14/coerce.html

 

coerce | Elasticsearch Guide [7.14] | Elastic

Data is not always clean. Depending on how it is produced a number might be rendered in the JSON body as a true JSON number, e.g. 5, but it might also be rendered as a string, e.g. "5". Alternatively, a number that should be an integer might instead be ren

www.elastic.co