HiveQL은 ANSI SQL 과 호환되는 부분이 많기는 하지만, RDBMS와는 차이가 많다. 따라서 SQL을 작성하는 과정에서 꼭 공식문서를 참고하는 것이 좋다.
HiveQL의 가장 큰 특징은 row의 PK가 없다는 것이다. 이에 따라서 query를 활용하는 방식도 다르니 주의해야한다.
CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.] table_name
[(col_name data_type [column_constraint] [COMMENT col_comment], ...)]
[PARTITIONED BY (col_name data_type [COMMENT 'col_comment'], ...)]
[CLUSTERED BY (col_name, col_name,.......]
[COMMENT table_comment]
[ROW FORMAT row_format]
[FIELDS TERMINATED BY char]
[LINES TERMINATED BY char]
[LOCATION 'hdfs_path']
[STORED AS file_format]
beeline -u jdbc:hive2://localhost:10000/default -n hive
create external table airline
(
Year int
,Month int
,DayofMonth int
,DayOfWeek int
,DepTime int
,CRSDepTime int
,ArrTime int
,CRSArrTime int
,UniqueCarrier string
,FlightNum int
,TailNum int
,ActualElapsedTime int
,CRSElapsedTime int
,AirTime int
,ArrDelay int
,DepDelay int
,Origin string
,Dest string
,Distance int
,TaxiIn int
,TaxiOut int
,Cancelled boolean
,CancellationCode char(1)
,Diverted boolean
,CarrierDelay int
,WeatherDelay int
,NASDelay int
,SecurityDelay int
,LateAircraftDelay int
)
ROW FORMAT SERDE'org.apache.hadoop.hive.serde2.OpenCSVSerde'
STORED AS TEXTFILE
location "hdfs://ha-nn-uri/user/hive/warehouse/default.db/airline" /* same to "warehouse/default.db/airline" */
hive
user 인 경우 /user/hive
가 기본경로location "hdfs://ha-nn-uri/user/hive/warehouse/default.db/airline"
에서 ha-nn-uri
는 어디서 왔냐?vi /etc/hadoop/conf.empty/core-site.xml
들어가보면 name : fs.defaultFS
, value :hdfs://ha-nn-uri
로 되어 있음hdfs dfs ls root
하면 이 HDFS 클러스터 네임 스페이스의 루트로 접근하게 되는 것.ROW FORMAT SERDE'org.apache.hadoop.hive.serde2.OpenCSVSerde'
: FIELDS TERMINATED BY char
,LINES TERMINATED BY char
안 쓰더라도 여기에서 파싱을 해준다.show create table airline;
Insert는 꼭 메뉴얼을 읽고 시작해야함.
매뉴얼
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement;
💡 그래서 메타데이터 데이터 베이스를 hive 로 이용하고 싶을 때는, DB를 통째로 덤프한 hive 테이블을 읽도록 디자인한다.
메타데이터 데이터베이스를 Hive로 이용하고자 할 때, 보통 DB를 통째로 덤프한 Hive 테이블을 읽도록 설계한다. 이는 유저의 행동 이벤트 데이터를 분석할 때 주로 필요하다.
예를 들어, 이벤트 데이터는 userid, action, time과 같은 형태로 들어오는데, 누가 어떤 행동을 얼마나 했는지 분석하기 위해서는 해당 유저의 메타데이터 정보가 필요하다. 따라서 이벤트 데이터를 분석하려면 메타데이터 테이블과 조인이 필수적이다.
이러한 경우, 메타데이터를 실시간으로 조회하는 대신, 일정 주기(예: 1시간 단위)로 DB 전체를 Hive 테이블로 덤프하고, 조인 시 최신 덤프 테이블만 사용하도록 설계하는 방식이 많이 활용된다.
예를 들어 1시 단위로 덤프한 테이블을 hour1이라 하고, 2시 단위 덤프는 hour2라 하면, 2시에 들어온 데이터를 분석할 때는 hour2 테이블만 참조하여 조인한다. 이렇게 하면 대용량 이벤트 데이터와 메타데이터를 효율적으로 결합할 수 있다.
거의 쓸 일은 없겠지만 실습을 해 보자.
create table emp (
empno int
,user_name string
,age int
,dept string
);
insert into table emp values (1, "Paul", 24, "engineering");
insert into table emp values (2, "John", 25, "engineering");
insert into table emp values (3, "Nancy", 21, "marketing");
insert into table emp values (3, "Yarn", 29, "engineering");
select * from emp limit 4;
LOAD DATA는 HIVE명령어 인데,
HDFS 또는 다른 저장소에 있는 데이터를 table 로 mv 또는 copy한다.
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)] [INPUTFORMAT 'inputformat' SERDE 'serde'] (3.0 or later)
[LOCAL]
경로가 local하면 이 스크립트 실행하는 로컬머신에 있는 file path 고 이걸 안 주고 INPATH
에서 그냥 하면 요거는 HDFS에서 찾는 path.load data
커맨드는 hive 의 table 의 경로로 데이터를 copy/move 하는 것이므로 주의한다.INTO TABLE tablesname
: 테이블에서 아까 Create table 할 때 지정된 location 으로 옮기게 된다.LOAD DATA INPATH '/data/input' INTO TABLE airline INPUTFORMAT 'textfile' SERDE'org.apache.hadoop.hive.serde2.OpenCSVSerde';
금방 된다. 왜냐면 그냥 HDFS에서 HDFS로, 같은 클러스터에서 옮기는 거니까. 사실상 경로만 바뀌게 됨.
조회
select year, month, dayofmonth as day, origin, deptime, dest, arrtime, distance, ActualElapsedTime as elapsed_t
from airline
limit 3;
이후 실습을 위해 원본을 복원한다.
#!/bin/bash
from="/user/hive/warehouse/default.db/airline/*.csv"
to="/data/input"
hdfs dfs -cp $from $to/
Select 는 일반 SQL과 사용법이 유사하다. 자세한 내용은 매뉴얼을 참고하는 것이 가장 정확하다.
[WITH CommonTableExpression (, CommonTableExpression)*] (Note: Only available starting with Hive 0.13.0)
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT [offset,] rows]
select DepDelay, year, month, dayofmonth as day, origin, deptime, dest, arrtime, distance
from airline
where Year=2008
and DepDelay > 0
order by DepDelay desc
limit 10;
위 명령어를 입력하면 Tez에서 실행 계획을 세우고 실행을 함.
UPDATE tablename SET column = value [, column = value ...] [WHERE expression]
Alter table 을 통해서 table 의 속성이나 schema, partition 정보 등을 변경할 수 있다.
Alter table 은 테이블의 속성을 변경하는 것인만큼 주의해서 사용해야한다.
대상되는 데이터가 많다 보니 Alter Talbe을 수행하는 몇몇 오퍼레이션들은 굉장히 부하를 많이 받을 수도 있고 실패할 수도 있음
항상 매뉴얼을 확인하자.
대표적으로 많이 사용하는 alter table 명령어 몇 개만 알아보자.
ALTER TABLE table_name RENAME TO new_table_name;
ALTER TABLE emp RENAME TO emp_2;
show create table emp_2;
show create table emp;
ALTER TABLE table_name [PARTITION partition_spec] CHANGE [COLUMN] col_old_name col_new_name column_type
[COMMENT col_comment] [FIRST|AFTER column_name] [CASCADE|RESTRICT];
column의 이름 변경이 필요할 때 사용한다.
타입변경은 replace column 을 해야한다.
alter table emp_2 change column empno emp_no int;
ALTER TABLE table_name
[PARTITION partition_spec] -- (Note: Hive 0.14.0 and later)
ADD|REPLACE COLUMNS (col_name data_type [COMMENT col_comment], ...)
[CASCADE|RESTRICT] -- (Note: Hive 1.1.0 and later)
alter table emp_2 add columns (adding string);
alter table emp_2 replace columns (emp_no bigint, user_name string, age int, dept string);
show create table emp_2;
select * from emp_2 limit 5;
alter table emp_2 replace columns (emp_no bigint, user_name string, age int, dept string);
show create table emp_2;
select * from emp_2 limit 5;
add partition을 하려면 External table을 선언하고 데이터를 원래 load를 해 놔야 함.
ℹ️ 실습에 사용하는 데이터는, P08-C02 AWS EMR Hadoop 실습 > 2 실습용 데이터 다운로드 에서 세팅한 데이터를 사용한다.
다음 script 로 /data/input 에 있는 연도별 데이터를 파티션 디렉토리 구성에 맞게 copy한다.
vi cp-data-hive.sh
실습을 위해 아래 내용 복붙하자
#!/bin/bash
hdfs dfs -mkdir /user/hive/warehouse/default.db/airline_partition
for year in {1987..2008}
do
hdfs dfs -mkdir /user/hive/warehouse/default.db/airline_partition/year=${year}
hdfs dfs -cp /data/input/${year}.csv /user/hive/warehouse/default.db/airline_partition/year=${year}/${year}.csv
done
./cp-data-hive.sh
table 을 선언한다.
create external table airline_partition
(
Month int
,DayofMonth int
,DayOfWeek int
,DepTime int
,CRSDepTime int
,ArrTime int
,CRSArrTime int
,UniqueCarrier string
,FlightNum int
,TailNum int
,ActualElapsedTime int
,CRSElapsedTime int
,AirTime int
,ArrDelay int
,DepDelay int
,Origin string
,Dest string
,Distance int
,TaxiIn int
,TaxiOut int
,Cancelled boolean
,CancellationCode char(1)
,Diverted boolean
,CarrierDelay int
,WeatherDelay int
,NASDelay int
,SecurityDelay int
,LateAircraftDelay int
)
PARTITIONED BY (year int)
ROW FORMAT SERDE'org.apache.hadoop.hive.serde2.OpenCSVSerde'
STORED AS TEXTFILE
location "hdfs://ha-nn-uri/user/hive/warehouse/default.db/airline_partition" /* same to "warehouse/default.db/airline" */
;
PARTITIONED BY (year int)
에 해당하는 컬럼은 create external table talbename
에서 빠져야 함데이터를 조회해본다.
select year, month, dayofmonth as day, origin, deptime, dest, arrtime, distance, ActualElapsedTime as elapsed_t
from airline_partition
limit 3;
add partition
ALTER TABLE airline_partition ADD PARTITION (year='1987') location '/user/hive/warehouse/default.db/airline_partition/year=1987';
다시 조회해본다.
select year, month, dayofmonth as day, origin, deptime, dest, arrtime, distance, ActualElapsedTime as elapsed_t
from airline_partition
limit 3;
1987 이 아닌 다른 year 조건으로 조회해본다.
select year, month, dayofmonth as day, origin, deptime, dest, arrtime, distance, ActualElapsedTime as elapsed_t
from airline_partition
where year=2008
limit 3;
external table 인 경우, 데이터의 변경사항이 hive table 에 실시간으로 반영되지 않는다.
그동안 업데이트된 데이터를 한 번에 hive 테이블에 반영하고 싶을 때, MSCK를 쓴다.
주의할 점은, 데이터가 많으면 MSCK 작업이 오래걸릴 뿐만 아니라 부하 때문에 OOM으로 죽을 수도 있다.
이 경우 partition 별로 나누어서 수행하거나, batch.size 를 설정한다.
MSCK [REPAIR] TABLE table_name [ADD/DROP/SYNC PARTITIONS];
[ADD/DROP/SYNC PARTITIONS]
옵션들을 주지 않아도 알아서 잘 적용을 함조회
set hive.msck.repair.batch.size;
=
이 없으면 조회하는 것.세팅
set hive.msck.repair.batch.size=$num;
앞서서 추가하지 못한 남은 파티션을 msck 로 추가한다.
set hive.msck.repair.batch.size=3;
msck repair table airline_partition;
다시 조회해본다.
select year, month, dayofmonth as day, origin, deptime, dest, arrtime, distance, ActualElapsedTime as elapsed_t
from airline_partition
where year=2008
limit 3;
5.4.1
실습 쿼리를 다시 수행해보고, 조회 속도를 비교해본다.
select DepDelay, year, month, dayofmonth as day, origin, deptime, dest, arrtime, distance
from airline_partition
where Year=2008
and DepDelay > 0
order by DepDelay desc
limit 10;
TEZ UI에서 작업에 걸린 시간을 확인한다.