Hadoop Ecosystem/Hive

[하이브 완벽 가이드] Ch5. HiveQL : 데이터 조작(DML)

은재정 2022. 9. 16. 22:49

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


Managed 테이블에 데이터 로딩하기

하이브는 로우 레벨에서 삽입, 갱신, 삭제를 지원하지 않습니다. 데이터를 테이블에 넣는 유일한 방법은 벌크로 로딩하는 것뿐입니다. 아니면 테이블 디렉터리에 직접 파일을 복사할 수 있습니다.

 

LOAD DATA 명령어를 명령어를 사용하여 데이터를 테이블에 로드합니다. 

 

LOAD DATA LOCAL INPATH '${env:HOME}/california-employees'
OVERWRITE INTO TABLE employees
-- 파티션된 테이블이 아니라면 아래 절은 생략 가능
PARTITION (country='US', state='CA');

 

이 명령은 해당 파티션을 위한 디렉터리가 존재하지 않을 때 디렉터리를 생성하고 여기에 데이터를 복사합니다. 파일 위치값은 개별 파일보다는 파일이 위치한 디렉터리를 지정하는 것이 일반적이고 이때 하이브는 해당 디렉터리 밑에 있는 모든 파일을 테이블의 디렉터리로 복사합니다. 

 

LOCAL 예약어를 사용하면 파일 위치는 로컬 파일시스템에 존재하는 것으로 간주하며 데이터는 테이블 디렉터리로 복사됩니다. LOCAL 예약어를 생략하면 해당 파일은 분산 파일시스템에 존재하는 것으로 간주하며 파일은 복사되는 것이 아니라 테이블 디렉터리로 이동합니다.

 

OVERWRITE 예약어를 사용하면 대상이 되는 디렉터리 내의 모든 파일을 삭제합니다. 사용하지 않는다면 새로운 파일을 대상 디렉터리 내에 추가합니다. 파일의 이름이 동일하다면 새로운 파일로 덮어씁니다.

 

INPATH 절에 사용하는 경로의 또 다른 제약 사항은 해당 경로 밑에 하위 디렉터리가 존재해서는 안된다는 것입니다.

 

하이브는 로딩되는 데이터가 스키마에 적합한지 여부를 검사하지 않습니다. 그러나 파일 포맷이 테이블에 선언된 내용과 일치하는지는 검증합니다. 예를 들어 테이블이 SEQUENCEFILE 저장소로 지정되어 있다면 로딩되는 파일은 시퀀스 파일이어야만 합니다.

 

쿼리 결과를 테이블에 넣기

INSERT 문은 쿼리 결과로부터 데이터를 로딩할 수 있게 해줍니다. OVERWRITE 예약어를 이용하면 데이터를 교체할 수 있고 그 대신 INTO 예약어를 사용하면 하이브는 데이터를 교체하지 않고 원래 데이터에 추가합니다.

 

INSERT OVERWRITE TABLE employees PARTITION (country='US', state='OR')
SELECT * FROM staged_employees se
WHERE se.cnty = 'US' AND se.st = 'OR';

 

하이브는 입력 데이터를 한 번 읽어서 이를 다수의 테이블로 분산하는 문법을 제공합니다. INSERT OVERWRITE 절과 INSERT INTO 절을 혼용하여 사용할 수도 있습니다.

 

FROM staged_employees se
INSERT OVERWRITE TABLE employees PARTITION (country='US', state='OR')
SELECT * se.cnty = 'US' AND se.st = 'OR'
INSERT OVERWRITE TABLE employees PARTITION (country='US', state='CA')
SELECT * se.cnty = 'US' AND se.st = 'CA'
INSERT OVERWRITE TABLE employees PARTITION (country='US', state='IL')
SELECT * se.cnty = 'US' AND se.st = 'IL';

 

동적 파티션 삽입

다만 위의 문법을 사용해도 많은 파티션을 만들 때 매우 긴 SQL문을 사용해야 한다는 문제점이 있습니다. 이를 해결하기 위해 하이브는 동적 파티션 기능을 제공합니다. 이는 쿼리 인자를 기반으로 파티션을 추론하는 것입니다.

 

INSERT OVERWRITE TABLE employees PARTITION (country, state)
SELECT ..., se.cnty, se.st FROM stage_employees se;

 

하이브는 SELECT 절의 마지막 두 컬럼에서 파티션 키인 country와 state의 값을 알아서 결정합니다. 입력 테이블의 컬럼값이 결과 테이블의 파티션 컬럼값이 됩니다. 이는 컬럼 이름이 아니라 컬럼의 위치에 의해 결정되는 것입니다. 

 

동적 파티션과 정적 파티션을 섞어서 사용할수도 있습니다. 다만 정적 파티션 키는 동적 파티션 키의 앞 쪽에 위치해야 합니다.

 

INSERT OVERWRITE TABLE employees PARTITION (country='US', state)
SELECT ..., se.cnty, se.st FROM statged_employees se
WHERE se.cnty = 'US';

 

기본 설정에서 동적 파티션 기능은 꺼져 있으며 이를 사용하도록 설정하면 strict 모드로 동작합니다. 이는 최소 몇 개의 컬럼은 정적으로 사용하도록 하여 잘못 설계된 쿼리가 엄청나게 많은 파티션을 생성하는 사고를 방지합니다. 아래는 동적 파티션의 속성에 대한 설명입니다.

 

이름 기본값 설명
hive.exec.dynamic.partition false 동적 파티션 기능을 사용할지를 결정합니다.
hive.exec.dynamic.partition.mode strict 모든 파티션 컬럼이 동적으로 할당되길 원하면 nonstrict로 설정합니다.
hive.exec.max.dynamic.partitions.pernode 100 각 맵퍼/리듀서가 생성할 수 있는 동적 파티션의 최대 개수입니다. 단 하나의 태스크라도 이보다 많은 수의 파티션을 만들면 fatal error가 발생합니다.
hive.exec.max.dynamic.partitions +1000 동적 파티션을 사용하는 하나의 절이 만들 수 있는 동적 파티션의 최대 개수입니다. 이보다 많은 수의 파티션을 만들면 fatal error가 발생합니다.
hive.exec.max.created.files 100000 하나의 쿼리 내에서 만들 수 있는 파일의 최대 개수입니다. 생성된 파일의 수는 하둡 카운터의 값을 참조합니다. 생성된 파일 수의 합이 이 값을 초과하면 fatal error가 발생합니다.

 

예를 들어 동적 파티션을 이용하여 모든 파티션을 파티셔닝하려면 데이터를 삽입하기 전에 다음과 같은 속성을 미리 설정해야 합니다.

 

SET hive.exec.dynamic.partition=true;
SET hive.exec.dynamic.partition.mode=nonstrict;
SET hive.exec.max.dynamic.partitions.pernode=1000;

 

쿼리 하나로 테이블을 생성하고 데이터 로딩하기

테이블을 생성하고 쿼리 결과를 그 테이블에 삽입하는 작업을 다음과 같이 한 문장으로 할 수 있습니다.

 

CREATE TABLE ca_employees AS
SELECT name, salary, address
FROM employees se
WHERE se.state = 'CA';

 

이 기능은 크고 다루기 힘든 테이블로부터 사용하기 쉬운 작은 테이블을 추출하는 용도로 주로 쓰입니다. 이 기능은 외부 테이블에 대해서는 사용할 수 없습니다. 

 

데이터 꺼내기

데이터를 테이블 밖으로 꺼내기 위해서는

  1. 데이터 파일이 이미 원하는 형식으로 되어 있다면 데이터가 있는 디렉터리 혹은 파일 복사 (hadoop fs -cp 명령어 사용)
  2. INSERT ... DIRECTORY ... 절 사용

아래는 2번의 사용 예시입니다.

 

INSERT OVERWRITE LOCAL DIRECTORY '/tmp/ca_employees'
SELECT name, salary, address FROM employees
WHERE se.state = 'US';

 

이때 테이블의 필드 구분 기호가 문제될 수 있는데, 예를 들어 기본 구분자인 ^A 대신 ,를 사용하기 위해서는 원하는 포맷으로 설정된 임시 테이블을 정의한 다음 쿼리 결과를 저장하는 방법이 있습니다. 이 임시 테이블의 데이터를 가져와 INSERT OVERWRITE DIRECTORY를 사용하면 됩니다. 다만 주의할 점은 임시 테이블을 사용자가 직접 지워야 한다는 것입니다.