하이브

Q·2022년 11월 29일

Hadoop 완벽 가이드

목록 보기
12/13

12장 하이브

1. 개요

  • 하이브는 하둡 기반의 데이터 웨어하우징 프레임워크다
  • 페이스북의 급증하는 소셜네트워킹에서 매일 생성되는 대량의 데이터를 관리 하고, 학습 하기 위해 개발되었다.
  • 페이스북에서는 대량의 데이터를 HDFS에 저장한 후, HiveQL (하이브가 제공하는 SQL)을 이용해서 데이터를 분석한다.
  • HiveQL과 같이 SQL을 사용하는 방식이 모든 빅데이터 문제에 이상적인 해결책은 아지만, 대다수의 경우에는 데이터 분석에 상당히 효과적이다.

2. 동작방식 살펴보기

  • 일반적으로 하이브는 로컬 머신에서 사용함.
  • 사용자는 HiveQL을 작성한 후 실행하면, 하이브는 해당 질의문을 맵리듀스 Job으로 변환하여 하둡 클러스터에서 구동시킨다.
  • 하이브는 데이터를 테이블 형태로 표현한다.
  • HDFS에 저장된 데이터와 테이블 스키마 사이에서, 하이브가 매개체 역할을 한다.
  • 테이블 스키마와 같은 메타데이터는 메타스토어(metastore) 에 저장된다.

3. 하이브 설치하기

3.1 설치전 준비사항

  • 자바 6 이상
  • 하둡 클러스터
    • 하둡 클러스터는 로컬 모드, 의사 분산 모드, 완전 분산 모드로 설치할 수 있다.
    • 로컬 모드는 하둡 클러스터 설치시 기본 설정이며, 머신의 로컬 디스크를 사용한다.
    • 의사 분산 모드로 설정하면, 마치 분산된 환경에서 실행되는 것처럼 하둡을 실행할 수 있다.(참고; 의사 분산 모드로 하둡 실행하기)

3.2 하이브 설치하기

  • 하이브를 다운로드한다.

  • 압축을 푼다.

    tar -xzf hive-x.y.z.tar.gz
  • 하둡 경로를 설정한다.

    hive-env.sh

    # Set HADOOP_HOME to point to a specific hadoop install directory
    HADOOP_HOME=/home/hadoop/hadoop
  • 하이브 쉘을 실행한다.

    bin/hive

하이브 쉘

  • 하이브 쉘은 HiveQL의 명령어를 수행하기 위해 하이브와 상호작용하는 기본 방식이다.
  • HiveQL은 하이브의 쿼리 언어로, MySQL의 SQL과 유사하다.
  • SQL과 마찬가지로, HiveQL은 대소문자를 구분하지 않는다.

3.3 하이브 QL 사용 옵션

  • 테이블 목록 보기
    show tables ;

하이브를 처음 설치한 후, 위 명령어를 실행하면 수행하는데 몇 초 정도가 걸린다.
그 이유는 바로 그 시점에 메타스토어 데이터베이스가 로컬 머신에 생성되기 때문이다.
메타스토어 데이터베이스는 hive 명령어를 실행한 위치에 metastore_db 라는 이름의 디렉토리를 만들어서, 필요한 파일을 저장한다.

  • 비대화식 모드로 실행하기

    • -f 옵션: HiveQL 명령어가 저장된 파일을 실행하기

      hive -f script.q
    • -e 옵션: 명령어가 짧다면, 인라인 형태로 실행하기

      hive -e 'select * from dummy'

      dummy 테이블 만들기

      % echo 'X' > /tmp/dummy.txt
      % hive -e "create table dummy (value string) ; \
      load data local inpath '/tmp/dummy.txt' \
      overwrite into table dummy"
    • -S 옵션: 대화형과 비대화명 모두에서 하이브는 실행 과정에서 부수적으로 발생하는 정보(쿼리를 수행하기 위해 거린 시간 같은)을 표준 에러로 출력한다.
      쿼리에 대한 출력 결과만을 보려면, -S 옵션을 붙여 불필요한 메시지의 출력을 막을 수 있다.

      hive -S -e 'select * from dummy'

4. 예제 따라하기

우선 하둡을 로컬 모드로 실행한 상태에서, 예제를 따라해보자.

4.1 테이블 생성하기

create table records (year string, temperature int, quality int)
row format delimited
fields terminated by '\t' ;
  • 데이터 파일의 행은 개행문자로 분리된다
  • 각 행은 탭으로 필드를 구분한다.

4.2 데이터 로드하기

load data local inpath 'input/ncdc/micro-tab/sample.txt'
overwrite into table records ;
  • 지정된 로컬 파일을 하이브의 웨어하우스 디렉토리에 적재한다.
  • 하이브는 특별한 파일 포맷을 요구하지 않으므로, 파일을 파싱하거나, 내부 데이터베이스 포맷으로 데이터를 변환하지 않는다.
  • 파일은 있는 그대로 저장되고, 하이브에 의해 수정되지 않는다.
  • 결과적으로 하이브 테이블은 로컬 파일 시스템에 저장된다.(로컬 모드에서 fs.default.name 은 기본값으로 file://로 설정되므로)
  • 테이블은 /user/hive/warehouse , 즉 하이브의 웨어하우스 디렉터리의 서브 디렉터리에 저장된다.
    • hive.metasotre.warehouse.dir 속성으로 설정하며, 기본값이 /user/hive/warehouse다.
  • 따라서 records 테이블에 로드된 파일은 로컬 파일 시스템의 /user/hive/warehouse/records 디렉터리에서 찾을 수 있다.
    % ls /user/hive/wareouse/records/

4.3 데이터 조회하기

select year, max(temperature)
from records
where temperature !=9999
and (quality = 0 or quality = 1 or quality = 4 or quality = 5 or quality = 9 )
group by year ;
  • 쿼리를 실행하면, 하이브가 이 쿼리를 맵리듀스 잡으로 변환해서 실행한 후, 그 결과를 콘솔로 출력한다.

5. 의사분산 모드에서, 예제 따라하기

이제 하둡을 의사 분산 모드로 실행한 상태에서, 예제를 따라해보자.
테이블은 이미 생성된 상태이며, 스토리지만 변경하면 되므로 하이브의 유연함을 확인해볼 수 있다.

5.0 의사분산 모드로 하둡 변경하기

의사분산 모드로 하둡을 실행한다.

5.1 테이블 생성하기

앞에서 만든 테이블 정보는, 메타스토어에 저장되므로 따로 생성할 필요가 없다.

5.2 데이터 로드하기

load data local inpath 'input/ncdc/micro-tab/sample.txt'
overwrite into table records ;
  • 지정된 로컬 파일을 하이브의 웨어하우스 디렉토리, 여기에서는 하둡 파일 시스템에 적재한다.
  • 테이블은 /user/hive/warehouse , 즉 하이브의 웨어하우스 디렉터리의 서브 디렉터리에 저장된다.
  • 이제 records 테이블에 로드된 파일은 하둡 파일 시스템의 /user/hive/warehouse/records 디렉터리에서 찾을 수 있다.
% bin/hadoop fs -ls /user/hive/wareouse/records/

하둡 파일 시스템 디렉토리 생성

만일 하둡 클러스터 하나를 공유하는 하나 이상의 하이브 사용자를 지원하려면, 모든 사용자들이 파일 쓰기가 가능한 디렉토리를 만들 필요가 있다.
bin/hadoop fs -mkdir /tmp
bin/hadoop fs -chmod a+w /tmp
bin/hadoop fs -mkdir /user/hive/warehouse
bin/hadoop fs -chmod a+w /user/hive/warehouse

5.3 데이터 조회하기

select year, max(temperature)
from records
where temperature !=9999
and (quality = 0 or quality = 1 or quality = 4 or quality = 5 or quality = 9 )
group by year ;
  • 로컬 모드일 때와 그 결과가 동일함을 확인할 수 있다.

6. 메타스토어

메타스토어는 서비스와 데이터 백업 저장소로 나뉜다.
하이브로 작업할 때, 메타스토어를 사용자의 로컬 머신에서 실행하면 간편하다.
하지만 이러한 로컬 메타스토어 방식은 하이브 테이블 정의가 로컬 머신에 위치하므로, 다른 사용자와 정의를 공유해서 사용할 수 없다.
하이브에서는 총 3가지의 메타스토어 설정방식을 제공한다. 지금까지 사용한 방식은 임베디드 메타스토어 설정이다.
484쪽, 그림 12-2. 메타스토어 설정 참고

6.1 임베디드 메타스토어 설정

  • 메타데이터 서비스는 하이브 서비스와 동일한 JVM에서 실행되고, 로컬 디스크에 백업되는 임베디드 더비 데이터베이스 인스턴스를 포함한다.
  • 그러나 임베디드 더비 데이터베이스 인스턴스는 한 번에 디스크에 위치한 데이터베이스 파일 하나에만 접근할 수 있다.
  • 따라서, 사용자가 동일한 메타스토어를 공유하는 순간에 단 하나의 하이브 세션만 사용 가능하다.
  • 다른 세션에서 메타스토어로 연결을 시도하면 다음과 같은 에러가 발생한다.
Failed to start database 'metastore_db'

6.2 로컬 메타스토어 설정

  • 하이브의 서비스와 같은 프로세스에서 실행되지만, 동일 서버나 원격 서버에서 실행되는 데이터베이스로 연결된다.
  • JDBC와 호환되는 데이터베이스라면, 표 12-1(485쪽) 에 열거된 javax.jdo.option.* 속성을 설정하여 사용할 수 있다.
  • 독립형 메타스토어로 주로 MySQL이 사용된다. MySQL을 위한 JDBC 드라이버 JAR 파일이 하이브의 클래스 패스에 있어야 하므로, 간단히 하이브의 lib 디렉토리에 관련 JAR 파일을 위치시킨다.
  • MySQL을 로컬 메타스토어를 사용하도록 설정하려면, hive-site.xml에 아래와 같이 설정할 수 있다.
<property>
  <name>javax.jdo.option.ConnectionURL</name>
  <value>jdbc:mysql://lmdev002:3306/hive?createDatabaseIfNotExist=true</value>
  <description>JDBC connect string for a JDBC metastore</description>
</property>

<property>
  <name>javax.jdo.option.ConnectionDriverName</name>
  <value>com.mysql.jdbc.Driver</value>
  <description>Driver class name for a JDBC metastore</description>
</property>

<property>
  <name>javax.jdo.option.ConnectionUserName</name>
  <value>hive</value>
  <description>username to use against metastore database</description>
</property>

<property>
  <name>javax.jdo.option.ConnectionPassword</name>
  <value>hive</value>
  <description>password to use against metastore database</description>
</property>

6.3 원격 메타스토어 설정

  • 하나 이상의 메타스토어 서버가 하이브 서비스와는 별도의 프로세스에서 실행한다.

7. 전통적인 데이터베이스와의 비교

7.1 스키마 유형

RDBMS: 쓰기 스키마(schema on write)

  • 전통적인 데이버베이스에서는 데이터를 적재하는 시점에 테이블의 스키마를 검증한다.
  • 만일 적재되고 있는 데이터가 스키마에 부합되지 않으면, 그 데이터는 거부된다.
  • 쓰기 스키마는 더 빠른 쿼리 성능을 제공한다. 데이터베이스가 열 단위로 색인이 가능하고. 데? 압축을 사용할 수 있기 때문이다.
  • 그러나 데이터를 데이터베이스로 적재하는 시간이 상대적으로 더 오래 걸린다.

하이브: 읽기 스키마(schema on read)

  • 하이브는 적재 시점보다 쿼리가 발행될 때 데이터를 검증한다 ->
  • 하이브에서 데이터 적재 연산(laod)는 단순한 파일 이동에 불과하다.
  • 따라서 하이브는 테이블의 디렉토리 파일과, 관련 테이블의 스키마의 정합성을 검사하지 않는다.
  • 만약 정합성에 문제가 있다면, 쿼리가 실행된 후 누락된 필드에 대해 NULL을 반환하는 방식으로 확인할 수 있다.
  • 하지만 RDBMS에서는 DB 자체적으로 검증을 수행하는 대신, 하이브를 사용할 때는 검증작업을 사용자 스스로 해야 한다.
  • 반면 읽기 스키마는 데이터베이스 내부 형태로 데이터를 디스크로부터 읽거나, 파싱하거나, 직렬화할 필요가 없으므로, 적재가 매우 빠르다.
  • 적재 과정은 단지 파일 복사 또는 이동 연산으로 실행된다.
  • 데이터 분석의 목적에 따라 동일 데이터를 서로 다른 두 스키마로 다뤄야 하는 경우가 있다면, 읽기 스키마는 매우 훌륭한 유연성을 제공한다(관리 테이블)

7.2 갱신, 트랜잭션, 색인

  • 갱신: 하이브는 HDFS를 기반으로 동작하므로, 테이블 갱신은 새로운 테이블로 데이터를 변환하는 방식으로 수행된다.
  • 트랜잭션: 하이브는 테이블의 동시 접근성을 명확하게 정의해놓지 않았다. 따라서 응용 프로그램 레벨에서, 동시성 또는 잠금 방식을 직접 제공해야 한다.
  • 색인: 하이브는 색인을 지원하지 않는다.

8. HiveQL

HiveQL로 명명된 하이브의 SQL 표현 방식은 SQL-92 표준 명세서를 완벽하게 지원하지는 않는다.
참고) 488쪽, 표 12-2. SQL과 HiveQL 비교

8. 데이터 타입

하이브는 기본형과 복합형 데이터 타입 모두를 지원한다.

  • 기본형에는 숫자형, 불린, 문자형을 포함한다.
  • 복합형에는 배열, 맵, 구조체를 포함한다.
    참고) 490쪽, 표 12-3. 하이브 데이터 타입

9. 연산자와 함수

하이브는 관계형 연산자, 산술 연산자, 논리 연산자 등을 제공한다.
또한 하이브넨 다양한 함수를 내장하고 있다.

  • 하이브 내장 함수 목록 보기
    show functions
  • 하이브 내장 함수 도움말 보기
    describe function [function name]

10. 테이블

하이브 테이블은 논리적으로 저장된 데이터 와, 테이블의 레이아웃을 기술하는 관련 메타데이터 로 구성된다.
데이터는 로컬 파일 시스템이나 S3를 포함해서, 어떠한 파일 시스템에도 저장할 수 있으나, 일반적으로 HDFS를 사용한다.
메타데이터는 HDFS가 아니라 RDBMS에 저장한다.

다중 데이터베이스

현재 0.9 버전에서는 다중 데이터베이스를 지원한다.

10.1 관리 테이블과 외부 테이블

테이블을 생성할 때 하이브는 기본적으로 데이터를 직접 관리하게 되는데, 이는 데이터가 하이브가 관리하고 있는 웨어하우스 디렉토리로 이동한다는 뜻이다.
반대로 사용자는 외부 테이블을 생성해서, 웨어하우스 디렉터리 위부에서 데이터를 참조할 수 도 있다.
관리 테이블과 외부 테이블은 아래와 같은 차이가 있다.

데이터 적재 관점(load)

  • 관리테이블: 사용자가 데이터를 관리 테이블에 적재할 때, 데이터는 하이브의 웨어하우스 디렉토리로 이동한다.
    create table managed_table (dummy string) ;
    load data inpath 'user/tom/data.txt' into table managed_table ;
  • 외부 테이블: 외부 데이터의 위치는 테이블 생성 시간에 지정한다.
    create external table external_table (dummy string)
    location '/user/tom/external_table' ;
    load data inpath 'user/tom/data.txt' into table managed_table ;
    • 외부 테이블은 external 키워드를 사용한다.
    • 하이브는 외부 테이블을 직접 관리할 필요가 없다는 것을 알기 때문에, 데이터를 웨어하우스 디렉토리로 이동시키지 않는다.

데이터 삭제 관점(drop)

  • 관리 테이블: 메타데이터와 데이터를 포함하고 있는 테이블이 모두 삭제된다.
    driop table managed_table ;
  • 외부 테이블: 데이터는 건드리지 않은 채, 메타데이터만 삭제한다.
    driop table external_table ;
  • 대부분의 경우 두 테이블간에는 큰 차이가 없으며, 단순히 선호의 문제다.
  • 경험적으로 하이브만으로 데이터를 처리하려면 관리 테이블을, 같은 데이터셋에서 하이브 외에 다른 도구를 사용하기 원하면 외부 테이블을 사용한다.
  • 외부 테이블을 사용하는 주요 사용처는, 같은 데이터셋에 대해 다중 스키마를 연관시키려고 할 때다.

11. 파티션과 버켓

  • 일반적인 개념임. 필요하다면 내용 추가할 것

12. 저장 포맷

  • 하이브는 2차원으로 테이블 저장소를 관리한다.

  • 각각 행 포맷과 파일 포맷이다.

  • 행포맷은 행과 특정 행의 필드가 저장된 방법을 보여준다.

  • 행포맷은 직렬자-역질렬자(Serializer-Deserializer)의 혼성어인 SerDe라고 부른다.

  • SerDe는 테이블을 쿼리하는 경우와 같은 역직렬자의 역할을 수행할 때, 파일 내 바이트로부터 데이터의 행을 하이브가 내부적으로 사용 중인 객체로 역직렬화하여 그 데이터에 대한 연산을 수행한다.

  • INSERT나 CTAS(Create Table As Select)를 수행하는 경우와 같은 직렬자의 역할을 수행할 때, 하이브의 내부 표현에 해당되는 데이터 한 행을 추력 파일에 적합한 바이트로 직렬화한다.

  • 파일 포맷은 행 안에 있는 필드가 포장된 방법을 말한다.

  • 기본 저장 포맷: 구분자-텍스트

  • 기본적인 행 구분자는 탭 문자가 아니라 아스키 제어코드의 집합 중 Ctrl-A 문자(\001)다.

  • ARRAY나 STRUCT의 항목이나, MAP의 키/값 쌍을 구분하기 위해 사용되는 기본적인 컬렉션 항목 구분자는 Ctrl-B(\002)다. MAP에서 키와 값을 구분하기 위해 사용되는 기본적인 키/값 구분자는 Ctrl-C 문자(\003)이다.

  • 테이블의 행은 개행문자로 구분된다.

  • 기본적으로 하이브는 LazySimpleSerDe를 사용한다. Lazy가 접두사로 붙은 이유는, 필드가 실제 사용되는 시점에서만 역직렬화되기 때문이다.

  • 쪽, 표 12-4. 하이브 SerDe

  • RegexSerde : 파일에서 각 필드가 특정 구분자로 분리되지 않는 경우, 정규식을 활용....

    create table records (year string, temperature int, quality int)
    
    row format serde 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
    
    with serdeproperties (
    
    "input.regex" = ""
    
    ) ;
    
    load data local inpath 'input/ncdc/micro-tab/sample_raw.txt'
    overwrite into table records ;
  • input.regex는 행을 형성하는 한 라인의 텍스트를 열의 집합으로 전환시키는 역직렬화 과정에서 사용할 수 있는 정규표현식 패턴이다.

  • 데이터 적재 연산에서는 SerDe가 사용되지 않으며, 테이블에서 데이터를 검색할 때, SerDe가 역직렬화를 위해 호출된다.

  • 개발 시점에서는 테스트용으로 활용할 수 있으나, 성능이 좋지 않으므로 운영 시점에서는 사용하지 않는 것이 좋다.

13. 데이터 임포트하기

insert overwrite table
insert overwrite table target
select col1, col2
from source ;
  • 다중 테이블 삽입
from source
insert overwrite table target
select col1, col2 ;
from records2

insert overwrite table stations_by_year

select year, count(distinct station)
group by year

insert overwrite table stations_by_year

select year, count(1)

group by year;
  • 이 경우 원본 테이블이 서로 분리된 여러 출력을 생성할 때도 단 한번만 스캔된다. 따라서 다중 테이블 삽입은 여러 번의 insert문을 사용하여 여러 번 원본 테이블을 스캔하는 방식에 비해 효율적이다.
  • 하이브의 쿼리 결과를 새로운 테이블에 저장해야할 때가 있다. 쿼리 결과가 너무 커서 콘솔로 볼 수 없거나, 그 결과를 이용하여 또 다른 데이터 처리를 해야하는 경우다.
create table target
as
select col1, col2
from source ;

14. 테이블 삭제 및 변경하기

  • 하이브는 읽기 과정에서 스키마를 활용하므로, 테이블을 생성한 후에도 유연하게 테이블 정의를 변경할 수 있다. 그러나 대부분의 경우, 새로운 구조에 적합하도록 데이터를 마이그레이션하는 일은 사용자에게 그 책임이 있으므로 주의해야 한다.
  • 테이블 이름 변경하기
altr table source rename to target ;
  • alter table은 테이블 메타데이터를 갱신할 뿐만 아니라 새로운 이름을 반영하기 위해 기존 테이블 디렉터리를 이동한다. 즉, /user/hive/warehouse/source는 /user/hive/warehouse/target으로 변경된다.
  • 하이브는 열에 대한 정의를 변경하고, 새로운 열을 추가할 수 있다.
alter table target add columns (col3 string) ;
  • 테이블 삭제하기
drop table target ;
  • 테이블을 삭제하면, 테이블에 대한 메타데이터 뿐만 아니라 데이터까지 모두 삭제된다.
  • 반면에 외부 테이블의 경우에는 메타데이터만 삭제된다.
  • 테이블 내 모든 데이터를 삭제하지만, 테이블의 정의는 그대로 유지하고자 한다면, 단순히 데이터 파일만 삭제하면 된다.
bin/hadoop fs -rmr /user/hive/warehouse/target/* ;
  • 또는 like 키워드를 사용해서, 해당 테이블과 동일한 스키마를 가지는 테이블을 생성할 수도 있다.
create table target like source ;

15. 데이터 쿼리하기

15.1 정렬과 집계

  • 하이브이 데이터 정렬은 order by절로 수행할 수 있다.
  • 하지만 order by가 전체 정렬을 할 수 잇으려면, 리듀서 개수를 하나로 설정해야 한다. 하지만 이렇게 설정하면, 성능이 문제가 있게된다.
  • 전체 정렬이 필요 없다면(대개의 경우 부분 정렬이면 충분하다), 하이브의 비표준 확장인 sort by를 대신 사용할 수 있다. sort by는 리듀서당 정렬된 파일을 생성한다. osrt by는 리듀서당 정렬된 파일을 생성한다.
  • 때때로 특정 행이 특정 리듀서로 가도록 설계하면, 집계 연산을 활용할 수 있다. 이때 distribute by를 사용할 수 있다.
from records2

select year, temperature
distribute by year
sort by year asc, temperature desc ;
  • sort by와 distributed by에 의해 사용되는 여이 같다면, 둘 다를 지정하기 위해 약칭으로 cluster by를 사용할 수 있다.

15.2 조인

  • 하이브를 사용하면 맵리듀스에 비해 조인을 훨씬 쉽게 활용할 수 있다.

내부 조인

  • 일반적인 개념

외부 조인

  • 일반적인 개념

세미 조인

  • 하이브는 in 서브 쿼리를 지원하지 않는다. 이 대신에 left semi join을 사용할 수 있다.

맵 조인

15.3 서브쿼리

  • 일반적인 개념

15.4 뷰

  • 일반적인 개념

16. 사용자 정의 함수

  • 하이브는 사용자 정의 함수(UDF: User Defined Function)을 통해, 사용자 자신의 데이터 처리 코드를 플러그인하고, 하이브 쿼리에서 그 함수를 호출할 수 있는 방식을 제공한다.
  • UDF는 하이브가 개발된 언어인 자바로 작성해야 한다.
  • UDF는 세 종류가 있다.
    • UDF는 단일 행을 입력으로 받고, 그 결과로 단일 행을 출력한다.
    • UDAF는 다중 행을 입력을 받아서, 단일 행을 출력한다.
    • UDTF는 단일 행을 입력으로 받아서, 그 결과로 다중 행(테이블)을 출력한다.

참조

profile
Data Engineer

0개의 댓글