ConvertRecord 로 CSV 를 Parquet 으로 바꾸면 스키마 추론(Infer Schema)이 숫자처럼 보이는 값을 정수나 실수로 잡는다. 앞자리 0 이 있는 코드값이나 사업자번호가 숫자로 변환돼 값이 훼손된다. 파일마다 추론 결과가 달라져 스키마가 흔들리기도 한다.
추론에 맡기지 않고 스키마를 명시한다. Avro 스키마를 등록해 두고 리더와 라이터가 그 스키마를 쓰도록 한다.
Controller Services 에서 AvroSchemaRegistry 를 만들고 속성 이름을 스키마 이름으로, 값에 Avro 스키마 본문을 넣는다.
{
"type": "record",
"name": "MyRecord",
"fields": [
{ "name": "biz_no", "type": "string" },
{ "name": "name", "type": ["null", "string"], "default": null },
{ "name": "amount", "type": ["null", "double"], "default": null },
{ "name": "reg_date", "type": ["null", "string"], "default": null }
]
}
문자열로 유지하려는 컬럼은 string 으로 못 박는다. NULL 이 들어올 수 있는 컬럼은 union 타입으로 선언하고 기본값을 준다.
CSVReader 를 만들고 다음을 지정한다.
| 속성 | 값 |
|---|---|
| Schema Access Strategy | Use 'Schema Name' Property |
| Schema Registry | 위에서 만든 AvroSchemaRegistry |
| Schema Name | MyRecord |
| Treat First Line as Header | true |
| Value Separator | , 또는 \t |
| Quote Character | " |
ParquetRecordSetWriter 도 같은 레지스트리와 스키마 이름을 쓰도록 설정한다. 이렇게 하면 읽기와 쓰기가 동일한 스키마를 공유한다.
GetFile / ListHDFS+FetchHDFS
→ ConvertRecord (CSVReader → ParquetRecordSetWriter)
→ PutHDFS
값 자체를 손봐야 한다면 중간에 UpdateRecord 를 넣는다. Record Path 로 대상 컬럼을 지정하고 표현식으로 값을 바꾼다.
Replacement Value Strategy : Record Path Value
/biz_no → /biz_no
문자열로 강제 변환하려면 Literal Value 전략에서 표현식을 쓴다.
/amount → ${field.value:toString()}
변환 결과의 스키마를 직접 본다.
hdfs dfs -get /data/parquet/part-0.parquet /tmp/
parquet-tools schema /tmp/part-0.parquet
parquet-tools head -n 5 /tmp/part-0.parquet
Impala 나 Hive 에서 외부 테이블로 붙여 확인해도 된다. 컬럼 타입이 의도와 다르면 Parquet 파일 자체를 다시 만들어야 하므로, 대량 변환 전에 표본 몇 건으로 먼저 검증한다.
한 디렉터리 안의 Parquet 파일들이 서로 다른 스키마를 가지면 조회 시 오류가 난다. 추론에 맡기면 이런 상황이 쉽게 생긴다. 스키마를 고정하는 이유가 여기에 있다.