data engineering

hive external table, partitioning

qkqhxla1 2019. 1. 28. 19:19

나만 여기서 처음 이런식의 구조를 봤는지 모르겠다. hive에는 internal table과 external table이 있다. 


현재 시스템의 일부 데이터 파이프라인의 구조다.

몽고디비 -> csv -> hdfs 로 csv업로드 -> 하이브 이런식으로 파이프라인이 있는데, csv를 hdfs에 올리는 과정에서 계속 이슈가 생겼다. 다른 큰 잡들이 돌아가다 보니 csv를 hdfs로 업로드하는데 문제가 생겨서, 몽고디비 -> csv -> aws s3 -> 하이브 이런식으로 파이프라인을 변경하기로 했다. 


하이브에서는 어떻게 s3의 데이터를 가져갈까 생각했었는데 external구문으로 외부의 데이터를 가져와서 테이블을 만들수 있었다. s3에 데이터를 넣을때는 여러 버킷이 아닌 한 버킷에 데이터를 정리하기 위해 버킷 내부에 폴더를 만들어주고 그 안에 csv를 넣는다. 


보안상 글은 다 삭제했다. 이후 external로 만들고 location구문으로 s3의 위치를 적어준다. 


Use 디비명.;

DROP TABLE IF EXISTS 디비명.테이블_s3;

CREATE EXTERNAL TABLE IF NOT EXISTS 디비명.테이블_s3 (idnum string, ~~~~~~~~~생략)

row format delimited fields terminated by '\t' stored as textfile LOCATION 's3://버킷이름/폴더이름' tblproperties("skip.header.line.count"="1");


이처럼 LOCATION으로 s3위치를 적어준다. 마지막에 csv이름은 안 적어줬는데 폴더이름까지만 입력하면 알아서 아래의 csv를 읽어와서 하이브 테이블을 구성한다.


신기한 점은 여기서부터이다. hive의 external table은 테이블을 구성하는 원본 데이터(여기서는 s3)가 변경될 시에 테이블에도 바로 반영된다. 하이브에서 테이블을 만들었을때, s3의 데이터를 변경하고 하이브 테이블에 다시 적용을 하기위해 테이블을 드랍하고 다시만들거나.. 해야 할줄 알았는데 그게 아니라 변경사항이 자동으로 바로 적용이 된다.


신기해서 구글링을 해봤는데 아래와 같은 글이 있다.

https://www.quora.com/Difference-between-Hive-internal-tables-and-external-tables

첫번째 답변을 요약해 보았다.


--------------------

유닉스 시스템에서 하드 링크와 심볼릭 링크를 안다면 하이브의 internal table과 external table을 이해하는데 도움이 될 것입니다. 하드 링크와 심볼릭 링크를 몰라도 아래와 같은 예시로 설명할 수 있습니다.

모든 하이브에 있는 object는 hdfs의 레퍼런스입니다. DB는 기본적으로 hdfs의 폴더를 가리킵니다. 하이브 테이블은 DB가 하는것처럼 DB폴더 아래를 가리킵니다. 그리고 파일을 찾을때까지 노드의 끝까지 내려가며 참조합니다.


하이브 테이블은 생성시 external선언을 하지 않으면 모두 internal table입니다. internal table을 만들때 파일과 강력한 연결을 갖습니다. 그러니까.. 하이브 테이블을 드랍하면 구성하는 데이터도 사라집니다. 

하지만 external table은 internal table과 반대입니다. external table도 데이터의 참조를 갖지만, 데이터와 느슨한 연결을 유지합니다. external table을 드랍하면 데이터는 그대로 남아있습니다.

--------------------


그러니까.. internal table은 하드 링크고, external table은 심볼릭 링크와 비슷하다는 소리입니다. 
mysql external table을 검색해봤는데 딱히 검색 결과가 나오지 않는걸로 보아 mysql에는 지원하지 않는듯 싶습니다.(또는 제가 모르는 다른 이름으로 제공되거나.)

s3에 있는 데이터로 돌아가는 external table에서 파티셔닝을 아래처럼 해줄수 있다.
테이블을 create할때 PARTITIONED BY (dt string) 처럼 파티션을 하겠다고 넣어준다. 나같은경우는 dt라는 필드로 파티션을 건다는 소리이다. 위의 create문에 결합하면 이처럼 된다.
CREATE EXTERNAL TABLE IF NOT EXISTS 디비명.테이블_s3 (idnum string, ~~~~~~~~~생략)
PARTITIONED BY (dt string)

row format delimited fields terminated by '\t' stored as textfile LOCATION 's3://버킷이름/폴더이름' 
tblproperties("skip.header.line.count"="1");


s3에는 아래처럼 폴더를 만든다.

이 폴더들의 위치는 s3://버킷이름/폴더이름/dt=20190528 이다. 저 폴더 아래에 csv라던지 파티션 데이터들을 넣어두고 add partition을 해줘야 한다.


alter table 디비명.테이블_s3 add IF NOT EXISTS partition (dt='20190528')

location 's3://버킷이름/폴더이름/dt=20190528'; 

요런식으로 하면 20190528만 파티션이 추가가 된다. create시에 dt로 파티셔닝을 한다고 했지만 폴더만 만들고 끝이 아니다. alter로 add partition을 해줘야 각각의 폴더와 하이브 테이블이 서로 연결이 된다. 확인해보고 싶으면 add partition하지 않은 다른 날짜로 select를 해보면 결과 값이 안나옴을 확인할수 있다.

select * from 디비명.테이블_s3 where dt='20190528'

select * from 디비명.테이블_s3 where dt='20190529'