Hadoop Ecosystem/Hive

[하이브 완벽 가이드] Ch15. 하이브 파일과 레코드 포맷 사용자화

은재정 2022. 10. 29. 16:00

이 글은 하이브 완벽 가이드 책을 읽고 그 중 일부 내용을 정리한 글입니다.


파일 vs 레코드 포맷

하이브는 파일 포맷과 레코드 포맷을 명확하게 구분합니다. 파일 포맷은 레코드가 파일 안에서 인코딩되는 방식이고 레코드 포맷은 바이트 열이 레코드 안에서 인코딩되는 방식입니다. 하이브에서 파일 포맷을 선택하는 것은 레코드 포맷을 선택하는 것과 직결됩니다. 보통 CREATE TABLE 문에선 STORED AS TEXTFILE을 사용한 텍스트 파일을 이용합니다.

 

CREATE TABLE 문 파헤치기

CREATE TABLE 문에서 STORED AS TEXTFILE을 사용하면 DESCRIBE EXTENDED 명령으로 테이블을 살펴봤을 때 InputFormat과 OutputFormat이 다음과 같습니다.

 

  • inputFormat : org.apache.hadoop.mapred.TextInputFormat
  • outputFormat : org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat

 

STORED AS SEQUENCEFILE을 사용하면 다음과 같습니다.

 

  • inputFormat : org.apache.hadoop.mapred.SequenceFileInputFormat
  • outputFormat : org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat

 

하이브는 테이블에서 데이터를 읽을 때는 InputFormat을 사용하고, 테이블에 데이터를 쓸 때는 OutputFormat을 사용합니다.

 

파일 포맷

텍스트 파일 포맷은 grep, sed, awk와 같은 유닉스 텍스트 도구 등과 데이터를 공유하기 편리하고 파일의 내용을 직접 보고 수정하기 쉽습니다. 그러나 텍스트 포맷은 바이너리 포맷과 비교하면 저장 공간을 효과적으로 사용하지 못하기 때문에 압축을 사용하기도 합니다. 바이너리 포맷을 사용함으로써 텍스트 포맷보다 더 향상된 디스크 I/O와 효과적인 디스크 공간 사용, 두 가지 이득을 얻을 수 있습니다.

 

시퀀스 파일

파일 포맷의 첫 번째 대안으로 시퀀스 파일 포맷을 사용할 수 있습니다. STORED AS SEQUENCEFILE 문을 사용하여 지정합니다. 시퀀스 파일은 바이너리 키-값으로 구성된 플랫 파일입니다. 하이브는 쿼리를 맵리듀스 잡으로 변환할 때 레코드로 사용하기 위한 적당한 키-값 쌍을 정합니다.

 

하둡에서 시퀀스 파일은 표준으로 지원되지만 하둡 생태계 밖의 도구와 사용하기에는 조금 부적합할 수 있습니다. 시퀀스 파일은 블럭과 레코드 수준에서 압축이 가능하므로 디스크 공간 활용과 I/O를 최적화할 수 있고 병렬 처리를 위한 블록 단위 파일 분할도 가능합니다. 하이브에서는 또 다른 효과적인 바이너리 포맷인 RCFile을 기본적으로 지원합니다.

 

RC 파일

하둡과 하이브 저장 공간은 로우 기반이며 이는 대부분 효과적인 방법입니다. 대부분의 테이블은 1-20개 사이의 적은 수의 컬럼을 가지고 있기 때문입니다. 그러나 테이블이 수백 개의 컬럼을 가지고 있거나 컬럼값의 종류가 다양하지 않은 경우에는 컬럼 압축이 일반적으로 효과적입니다. 하이브의 RCFile은 이러한 시나리오를 위해 설계되었습니다. 

 

RCFile은 컬럼 지향 방식으로 테이블의 컬럼을 지정합니다. 우선 로우를 로우 스플릿으로 수평 파티셔닝한 다음, 각각의 로우 스플릿을 수직으로 컬럼 파티셔닝합니다. RCFile은 한 로우 스플릿의 메타데이터를 레코드의 키로 저장하고 로우 스플릿의 모든 데이터는 값으로 지정합니다. 

 

하이브는 서로 다른 두 데이터 포맷을 간단히 변환할 수 있다는 강력한 장점이 있습니다. 한 테이블을 SELECT한 값을 다른 테이블로 INSERT하면 하이브는 메타데이터를 사용해 테이블 간의 데이터 변환을 자동으로 수행합니다. 

 

RCFile은 시퀀스 파일을 여는 데 사용하는 도구로는 열 수 없고 하이브는 RCFile의 내용을 보여주는 rcfilecat 도구를 제공합니다.

 

레코드 포맷 : SerDe

SerDe는 직렬화/역직렬화의 약어입니다. 하이브는 파일을 읽을 때 파일포맷(FileFormat)을 이용하고, 디시리얼라이저(Deserializer)를 이용하여 원천 데이터를 테이블 포맷에 맞는 로우 데이터로 변환합니다. 파일을 쓸때는 로우 데이터를 시리얼라이저(Serializer)를 이용하여 키, 밸류 형태로 변경하고 파일포맷을 이용하여 저장 위치에 씁니다. 서데는 doDeserialize(), doSerialize() 를 구현하여 각각의 경우를 처리하게 됩니다.

 

  • HDFS files --> InputFileFormat --> [key, value] --> Deserializer --> Row object
  • Row object --> Serializer --> [key, value] --> OutputFileFormat --> HDFS files

 

JSON SerDe

JSON 데이터를 하이브를 통해 쿼리하기 원하는 상황이 있을 수 있습니다. 각각의 JSON 문서가 줄별로 분리되어 있다면 입력과 출력 포맷으로 TEXTFILE을 사용한 다음, JSON SerDe를 사용해 각각의 JSON 문서를 레코드로 파싱할 수 있습니다. 다음은 가상의 메시징 시스템을 위해 JSON SerDe를 사용하여 JSON 데이터로부터 몇몇 필드를 추출하는 예입니다.

 

CREATE EXTERNAL TABLE messages (
    msg_id    BIGINT,
    tstamp    STRING,
    text      STRING,
    user_id   BIGINT,
    user_name STRING
)
ROW FORMAT SERDE "org.apache.hadoop.hive.contrib.serde2.JsonSerde"
WITH SERDEPROPERTIES (
    "msg_id"="$.id",
    "tstamp"="$.created_at",
    "text"="$.text",
    "user_id"="$.user.id",
    "user_name"="$.user.name"
)
LOCATION '/data/messages';

 

WITH SERDEPROPERTIES는 하이브의 기능으로 사용자 정의 속성을 SerDe에 보낼 수 있고 SerDe는 속성을 보이는 대로 해석합니다. 위 예제에서는 속성값을 JSON 문서의 필드를 테이블의 컬럼으로 맵핑하는데 사용했습니다. \$.user.id 문자열은 $로 표현되는 각각의 레코드를 취한 후 맵 형태를 가진 레코드에서 user 키를 찾고 다시 userd에서 id 키의 값을 추출한다는 의미입니다. 한 번 정의하면 사용자는 JSON으로부터 데이터를 실제로 가져오는 것을 의식할 필요 없이 쿼리를 실행하면 됩니다.