하이브

하이브 (Hive)

이 문서에서는 StorageHandler를 사용해 하이브를 통해 아이스버그 테이블을 읽고 쓰는 방법을 알려드릴게요. Hive 4.0.0 이상에서 지원되는 기능들, 아이스버그 지원 활성화 방법, 카탈로그 관리, DDL·DML 명령, 타임 트래블, 컴팩션까지 하이브에서 아이스버그를 다루는 전반적인 내용을 살펴볼게요.

출처: 문서

본문

아이스버그는 StorageHandler를 사용해 하이브를 통해 아이스버그 테이블을 읽고 쓰는 것을 지원해요.

기능 지원 (Feature support)

하이브는 Hive 4.0.0 이상 버전에서 다음 기능을 지원해요.

  • 아이스버그 테이블 만들기.
  • 아이스버그 identity 파티션 테이블 만들기.
  • 아이스버그가 지원하는 다양한 변환을 포함해 어떤 파티션 스펙으로든 아이스버그 테이블 만들기.
  • 기존 테이블에서 테이블 만들기 (CTAS 테이블).
  • 테이블 드롭.
  • 아이스버그와 하이브 스키마를 동기화하면서 테이블 변경.
  • 파티션 스키마 변경 (컬럼 업데이트).
  • 파티션 변환을 지정해서 파티션 스키마 변경.
  • 테이블/파티션 잘라내기, 파티션 드롭.
  • Avro, Parquet, ORC(Non-ACID) 포맷의 테이블을 아이스버그로 마이그레이션.
  • 아이스버그 테이블 읽기.
  • 테이블 스키마 읽기.
  • 아이스버그 메타데이터 테이블 쿼리.
  • 타임 트래블 애플리케이션.
  • 테이블/파티션에 삽입 (INSERT INTO).
  • 테이블/파티션에서 기존 데이터를 덮어쓰며 삽입 (INSERT OVERWRITE).
  • delete, update, merge 쿼리를 위한 copy-on-write 지원, 아이스버그 V1 테이블의 CRUD 지원.
  • 스냅샷 만료와 함께 테이블 변경.
  • 기존 테이블과 같은 테이블 만들기 (CTLT 테이블).
  • 테이블 속성으로 parquet 압축 타입 추가 지원.
  • 테이블 메타데이터 위치 변경.
  • 테이블 롤백 지원.
  • 테이블을 쓸 때 기존 테이블의 정렬 순서 준수.
  • 아이스버그 브랜치/태그 만들기, 쓰기, 드롭.
  • 스냅샷 ID로, 시간 범위로, 마지막 N개 스냅샷 보존으로, 테이블 속성을 사용해 스냅샷 만료 허용.
  • 아이스버그 테이블의 현재 스냅샷을 스냅샷 ID로 설정.
  • 아이스버그 테이블 이름 변경 지원.
  • 아이스버그 테이블로 변환하도록 테이블 변경.
  • 아이스버그 브랜치로 fast forwarding, cherry-picking 커밋.
  • 아이스버그 태그에서 브랜치 만들기.
  • 아이스버그 테이블의 현재 스냅샷을 브랜치/태그로 설정.
  • 아이스버그 테이블의 고아 파일 삭제.
  • 아이스버그 테이블의 전체 테이블 컴팩션 허용.
  • 아이스버그 테이블의 파티션 정보 표시 지원 (SHOW PARTITIONS).

경고 (Warning)

DML 연산은 Tez 실행 엔진에서만 동작해요.

하이브에서 아이스버그 지원 활성화 (Enabling Iceberg support in Hive)

1.8.0부터 아이스버그는 Hive 런타임 커넥터를 릴리스하지 않아요. Hive 쿼리 엔진 통합(특히 Hive 2.x와 3.x)에는 Iceberg 1.6.1에 포함된 Hive 런타임 커넥터를 사용하거나, 임베디드 아이스버그 통합이 포함된 Hive 4.0.0 이상을 사용해주세요.

Hive 4.1.x, 4.2.x

Hive 4.1.x와 4.2.x에는 Iceberg 1.9.1이 포함돼 있어요.

Hive 4.0.x

Hive 4.0.x에는 Iceberg 1.4.3이 포함돼 있어요.

지원 활성화 (Enabling support)

Iceberg 스토리지 핸들러가 하이브의 클래스패스에 없으면, 스토리지 핸들러가 설정돼 있어도 하이브는 아이스버그 테이블의 메타데이터를 로드하거나 업데이트할 수 없어요. 하이브에 깨진 테이블이 나타나는 것을 피하기 위해, 아이스버그는 하이브 지원이 활성화되지 않는 한 테이블에 스토리지 핸들러를 추가하지 않아요. 스토리지 핸들러는 테이블에 대한 하이브 엔진 지원이 업데이트될 때마다, 즉 테이블 속성에서 켜지거나 꺼질 때마다 동기화(추가되거나 제거)돼요. 하이브 지원을 활성화하는 방법은 두 가지가 있어요: Hadoop 구성에서 전역적으로, 또는 테이블 속성을 사용해 테이블별로.

Hadoop 구성 (Hadoop configuration)

애플리케이션에 대해 하이브 지원을 전역적으로 활성화하려면 Hadoop 구성에서 iceberg.engine.hive.enabled=true를 설정해요. 예를 들어 스파크가 로드한 hive-site.xml에서 이것을 설정하면 스파크가 만든 모든 테이블에 대해 스토리지 핸들러가 활성화돼요.

테이블 속성 구성 (Table property configuration)

또는 engine.hive.enabled 속성을 true로 설정하고 아이스버그 테이블을 만들 때 테이블 속성에 추가할 수 있어요. 프로그래밍 방식으로 하는 예시는 다음과 같아요.

Catalog catalog=...;
    Map<String, String> tableProperties=Maps.newHashMap();
    tableProperties.put(TableProperties.ENGINE_HIVE_ENABLED,"true"); // engine.hive.enabled=true
    catalog.createTable(tableId,schema,spec,tableProperties);

테이블 수준 구성이 전역 Hadoop 구성을 재정의해요.

카탈로그 관리 (Catalog Management)

전역 Hive 카탈로그 (Global Hive catalog)

HiveCatalog 통합은 Hive 2.3.10 또는 3.1.3 이상을 지원해요.

하이브 엔진의 관점에서, 런타임 환경의 Hadoop 구성에 정의된 전역 데이터 카탈로그는 하나뿐이에요. 반면 아이스버그는 Hive, Hadoop, AWS Glue, 또는 커스텀 카탈로그 구현 같은 여러 다른 데이터 카탈로그 타입을 지원해요. 아이스버그는 또한 파일 시스템의 경로를 기반으로 테이블을 직접 로드하는 것도 허용해요. 그런 테이블은 어떤 카탈로그에도 속하지 않아요. 사용자는 조인 같은 사용 사례를 위해 하이브 엔진을 통해 이 교차 카탈로그 및 경로 기반 테이블을 읽고 싶을 수 있어요.

이를 지원하기 위해, 하이브 메타스토어의 테이블은 테이블의 iceberg.catalog 속성에 따라 아이스버그 테이블을 로드하는 세 가지 다른 방식을 나타낼 수 있어요.

  1. iceberg.catalog가 설정되지 않으면 테이블은 하이브 환경에 구성된 메타스토어에 해당하는 HiveCatalog로 로드돼요.
  2. iceberg.catalog가 카탈로그 이름으로 설정되면 커스텀 카탈로그로 로드돼요 (아래 참조).
  3. iceberg.catalog가 location_based_table로 설정되면 테이블의 루트 위치를 사용해 테이블을 직접 로드할 수 있어요.

위의 경우 2와 3의 경우, 사용자는 하이브 메타스토어에 아이스버그 테이블의 오버레이(overlay)를 만들어서 다른 테이블 타입이 같은 하이브 환경에서 함께 동작할 수 있게 해요. 자세한 내용은 CREATE EXTERNAL TABLE과 CREATE TABLE을 참고해주세요.

커스텀 아이스버그 카탈로그 (Custom Iceberg catalogs)

다른 카탈로그를 전역으로 등록하려면 다음 Hadoop 구성을 설정해요.

구성 키 설명
iceberg.catalog.<catalog_name>.type 카탈로그 타입: hive, hadoop, 또는 커스텀 카탈로그를 사용할 때 미설정
iceberg.catalog.<catalog_name>.catalog-impl 카탈로그 구현, type이 비어있으면 null이 아니어야 해요
iceberg.catalog.<catalog_name>. 카탈로그의 모든 구성 키-값 쌍

Hive CLI를 사용한 몇 가지 예시는 다음과 같아요.

another_hive라는 HiveCatalog 등록:

SET iceberg.catalog.another_hive.type=hive;
SET iceberg.catalog.another_hive.uri=thrift://example.com:9083;
SET iceberg.catalog.another_hive.clients=10;
SET iceberg.catalog.another_hive.warehouse=hdfs://example.com:8020/warehouse;

hadoop이라는 HadoopCatalog 등록:

SET iceberg.catalog.hadoop.type=hadoop;
SET iceberg.catalog.hadoop.warehouse=hdfs://example.com:8020/warehouse;

glue라는 AWS GlueCatalog 등록:

SET iceberg.catalog.glue.type=glue;
SET iceberg.catalog.glue.warehouse=s3://my-bucket/my/key/prefix;
SET iceberg.catalog.glue.lock.table=myGlueLockTable;

DDL 명령 (DDL Commands)

CREATE TABLE

비파티션 테이블 (Non partitioned tables)

Hive CREATE EXTERNAL TABLE 명령은 스토리지 핸들러를 지정하면 아이스버그 테이블을 만들어요.

CREATE EXTERNAL TABLE x (i int) STORED BY ICEBERG;

CREATE TABLE을 사용해 외부 테이블을 만들고 싶다면 클러스터에서 MetaStoreMetadataTransformer를 구성하면, CREATE TABLE 명령이 외부 테이블을 만들도록 변환돼요. 예를 들어:

CREATE TABLE x (i int) STORED BY ICEBERG;

테이블 생성 시 기본 파일 포맷(Avro, Parquet, ORC)을 지정할 수 있어요. 기본값은 Parquet이에요.

CREATE TABLE x (i int) STORED BY ICEBERG STORED AS ORC;

파티션 테이블 (Partitioned tables)

non-Iceberg 테이블을 만드는 것에 익숙한 명령으로 아이스버그 파티션 테이블을 만들 수 있어요.

CREATE TABLE x (i int) PARTITIONED BY (j int) STORED BY ICEBERG;

정보 (Info)

결과 테이블은 HMS에 파티션을 만들지 않고, 대신 파티션 데이터를 아이스버그 identity 파티션으로 변환해요.

DESCRIBE 명령으로 아이스버그 identity 파티션에 대한 정보를 얻어요.

DESCRIBE x;

결과는:

col_name data_type comment
i int
j int
NULL NULL
# Partition Transform Information NULL NULL
# col_name transform_type NULL
j IDENTITY NULL

다음 아이스버그 파티션 스펙 구문으로 아이스버그 파티션을 만들 수 있어요 (Hive 4.0.0부터 지원).

CREATE TABLE x (i int, ts timestamp) PARTITIONED BY SPEC (month(ts), bucket(2, i)) STORED BY ICEBERG;
DESCRIBE x;

결과는:

col_name data_type comment
i int
ts timestamp
NULL NULL
# Partition Transform Information NULL NULL
# col_name transform_type NULL
ts MONTH NULL
i BUCKET[2] NULL

하이브가 지원하는 변환은 스파크와 같아요.

  • years(ts): 연 단위 파티션
  • months(ts): 월 단위 파티션
  • days(ts) 또는 date(ts): dateint 파티셔닝과 동등
  • hours(ts) 또는 date_hour(ts): dateint 및 hour 파티셔닝과 동등
  • bucket(N, col): 해시 값 mod N 버킷으로 파티션
  • truncate(L, col): L로 잘린 값으로 파티션. 문자열은 주어진 길이로 잘리고, 정수와 long은 빈으로 잘림: truncate(10, i)는 파티션 0, 10, 20, 30, ...을 생성

정보 (Info)

결과 테이블은 HMS에 파티션을 만들지 않고, 대신 파티션 데이터를 아이스버그 파티션으로 변환해요.

CREATE TABLE AS SELECT

CREATE TABLE AS SELECT 연산은 하나의 중요한 차이점을 제외하고 네이티브 Hive 연산과 비슷해요. 아이스버그 테이블과 해당 하이브 테이블은 쿼리 실행이 시작될 때 만들어져요. 데이터는 쿼리가 끝날 때 삽입/커밋돼요. 그래서 일시적인 기간 동안 테이블이 이미 존재하지만 데이터가 없어요.

CREATE TABLE target PARTITIONED BY SPEC (year(year_field), identity_field) STORED BY ICEBERG AS
    SELECT * FROM source;

CREATE TABLE LIKE TABLE

CREATE TABLE target LIKE source STORED BY ICEBERG;

기존 아이스버그 테이블을 덮는 CREATE EXTERNAL TABLE (CREATE EXTERNAL TABLE overlaying an existing Iceberg table)

CREATE EXTERNAL TABLE 명령은 기존 아이스버그 테이블 "위에(top of)" Hive 테이블을 덮는(overlay) 데 사용돼요. 아이스버그 테이블은 Catalog 또는 Tables 인터페이스의 구현으로 만들어지고, 하이브는 이런 다양한 타입의 테이블을 작업하도록 그에 맞게 구성되어야 해요.

Hive 카탈로그 테이블 (Hive catalog tables)

앞서 설명한 대로, HiveCatalog가 Hive 엔진 기능을 활성화해 만든 테이블은 하이브 엔진에 직접 보이므로 오버레이를 만들 필요가 없어요.

커스텀 카탈로그 테이블 (Custom catalog tables)

등록된 카탈로그의 테이블에 대해, 테이블 속성 iceberg.catalog으로 카탈로그 이름을 문에서 지정해요. 예를 들어 아래 SQL은 hadoop_cat이라는 hadoop 타입 카탈로그의 테이블에 대한 오버레이를 만들어요.

SET
iceberg.catalog.hadoop_cat.type=hadoop;
SET
iceberg.catalog.hadoop_cat.warehouse=hdfs://example.com:8020/hadoop_cat;

CREATE
EXTERNAL TABLE database_a.table_a
STORED BY 'org.apache.iceberg.mr.hive.HiveIcebergStorageHandler'
TBLPROPERTIES ('iceberg.catalog'='hadoop_cat');

iceberg.catalog이 테이블 속성과 전역 Hadoop 구성 모두에서 누락되면 HiveCatalog가 기본값으로 사용돼요.

경로 기반 Hadoop 테이블 (Path-based Hadoop tables)

HadoopTables로 만든 아이스버그 테이블은 HDFS 같은 파일 시스템의 디렉터리에 전체가 저장돼요. 이 테이블들은 카탈로그가 없는 것으로 간주돼요. 이를 나타내려면 iceberg.catalog 속성을 location_based_table로 설정해요. 예를 들어:

CREATE
EXTERNAL TABLE table_a 
STORED BY 'org.apache.iceberg.mr.hive.HiveIcebergStorageHandler' 
LOCATION 'hdfs://some_bucket/some_path/table_a'
TBLPROPERTIES ('iceberg.catalog'='location_based_table');

기존 아이스버그 테이블을 덮는 CREATE TABLE (CREATE TABLE overlaying an existing Iceberg table)

커스텀 카탈로그가 관리하는 새 테이블을 만들 수도 있어요. 예를 들어 다음 코드는 커스텀 Hadoop 카탈로그에 테이블을 만들어요.

SET
iceberg.catalog.hadoop_cat.type=hadoop;
SET
iceberg.catalog.hadoop_cat.warehouse=hdfs://example.com:8020/hadoop_cat;

CREATE TABLE database_a.table_a
(
    id   bigint,
    name string
) PARTITIONED BY (
  dept string
) STORED BY 'org.apache.iceberg.mr.hive.HiveIcebergStorageHandler'
TBLPROPERTIES ('iceberg.catalog'='hadoop_cat');

위험 (Danger)

만들 테이블이 커스텀 카탈로그에 이미 존재하면, 이는 관리형(managed) 오버레이 테이블을 만들어요. 즉 기술적으로 오버레이 테이블을 만들 때 EXTERNAL 키워드를 생략할 수 있어요. 하지만 이것은 권장되지 않아요. 관리형 오버레이 테이블을 만들면 하이브 측의 우발적인 drop table 명령으로 공유 데이터 파일이 위험해질 수 있고, 의도치 않게 테이블의 모든 데이터가 제거될 수 있기 때문이에요.

ALTER TABLE

테이블 속성 (Table properties)

HiveCatalog 테이블의 경우 HMS에 저장된 아이스버그 테이블 속성과 하이브 테이블 속성이 동기화돼요.

정보 (Info)

중요: 이 기능은 다른 카탈로그 구현에서는 사용할 수 없어요.

ALTER TABLE t SET TBLPROPERTIES('...'='...');

스키마 진화 (Schema evolution)

Hive 테이블 스키마는 아이스버그 테이블과 동기화돼요. 외부 소스(Impala/Spark/Java API 등)가 스키마를 바꾸면 Hive 테이블이 즉시 변경을 반영해요. Hive 명령으로 테이블 스키마를 변경할 수 있어요.

  • 테이블 이름 변경: ALTER TABLE orders RENAME TO renamed_orders;
  • 컬럼 추가: ALTER TABLE orders ADD COLUMNS (nickname string);
  • 컬럼 이름 변경: ALTER TABLE orders CHANGE COLUMN item fruit string;
  • 컬럼 순서 변경: ALTER TABLE orders CHANGE COLUMN quantity quantity int AFTER price;
  • 컬럼 타입 변경 - 아이스버그가 컬럼 타입 변경을 안전하게 정의한 경우에만: ALTER TABLE orders CHANGE COLUMN price price long;
  • REPLACE COLUMN으로 이전 컬럼을 제거해 컬럼 드롭: ALTER TABLE orders REPLACE COLUMNS (remaining string);

정보 (Info)

컬럼 드롭이 REPLACE COLUMNS를 사용할 수 있는 유일한 작업이라는 점에 유의해주세요. 즉 컬럼이 순서가 바뀌어 지정되면 이 제한을 알리는 오류가 발생해요.

파티션 진화 (Partition evolution)

다음 명령으로 파티셔닝 스키마를 변경할 수 있어요.

  • 새 identity 파티션으로 파티셔닝 스키마 변경: ALTER TABLE default.customers SET PARTITION SPEC (last_name);
  • 또는 파티션 스펙 제공: ALTER TABLE order SET PARTITION SPEC (month(ts));

테이블 마이그레이션 (Table migration)

다음 명령으로 Avro / Parquet / ORC 외부 테이블을 아이스버그 테이블로 마이그레이션할 수 있어요.

ALTER TABLE t SET TBLPROPERTIES ('storage_handler'='org.apache.iceberg.mr.hive.HiveIcebergStorageHandler');

마이그레이션 동안 데이터 파일은 변경되지 않고 적절한 아이스버그 메타데이터 파일만 만들어져요. 마이그레이션 후에는 테이블을 일반 아이스버그 테이블로 다뤄주세요.

파티션 드롭 (Drop partitions)

단일/다중 파티션 스펙을 기반으로 다음 명령으로 파티션을 드롭할 수 있어요.

ALTER TABLE orders DROP PARTITION (buy_date == '2023-01-01', market_price > 1000), PARTITION (buy_date == '2024-01-01', market_price <= 2000);

파티션 스펙은 identity 파티션 컬럼만 지원해요. 파티션 스펙의 변환 컬럼은 지원되지 않아요.

브랜치와 태그 (Branches and tags)

ALTER TABLE ... CREATE BRANCH

다음 옵션으로 CREATE BRANCH 문을 통해 브랜치를 만들 수 있어요.

  • 기본 속성으로 브랜치 만들기.
  • 특정 스냅샷 ID에서 브랜치 만들기.
  • 시스템 시간 사용해서 브랜치 만들기.
  • 지정된 수의 스냅샷 보존으로 브랜치 만들기.
  • 특정 태그 사용해서 브랜치 만들기.
-- CREATE branch1 with default properties.
ALTER TABLE test CREATE BRANCH branch1;

-- CREATE branch1 at a specific snapshot ID.
ALTER TABLE test CREATE BRANCH branch1 FOR SYSTEM_VERSION AS OF 3369973735913135680;

-- CREATE branch1 using system time.
ALTER TABLE test CREATE BRANCH branch1 FOR SYSTEM_TIME AS OF '2023-09-16 09:46:38.939 Etc/UTC';

-- CREATE branch1 with a specified number of snapshot retentions.
ALTER TABLE test CREATE BRANCH branch1 FOR SYSTEM_VERSION AS OF 3369973735913135680 WITH SNAPSHOT RETENTION 5 SNAPSHOTS;

-- CREATE branch1 using a specific tag.
ALTER TABLE test CREATE BRANCH branch1 FOR TAG AS OF tag1;

ALTER TABLE ... CREATE TAG

다음 옵션으로 CREATE TAG 문을 통해 태그를 만들 수 있어요.

  • 기본 속성으로 태그 만들기.
  • 특정 스냅샷 ID에서 태그 만들기.
  • 시스템 시간 사용해서 태그 만들기.
-- CREATE tag1 with default properties.
ALTER TABLE test CREATE TAG tag1;

-- CREATE tag1 at a specific snapshot ID.
ALTER TABLE test CREATE TAG tag1 FOR SYSTEM_VERSION AS OF 3369973735913135680;

-- CREATE tag1 using system time.
ALTER TABLE test CREATE TAG tag1 FOR SYSTEM_TIME AS OF '2023-09-16 09:46:38.939 Etc/UTC';

ALTER TABLE ... DROP BRANCH

다음 옵션으로 DROP BRANCH 문을 통해 브랜치를 드롭할 수 있어요.

  • 그렇지 않으면 존재하지 않는 브랜치에서 IF EXISTS로 실패하지 않기
-- DROP branch1
ALTER TABLE test DROP BRANCH branch1;

-- DROP branch1 IF EXISTS
ALTER TABLE test DROP BRANCH IF EXISTS branch1;

ALTER TABLE ... DROP TAG

다음 옵션으로 DROP TAG 문을 통해 태그를 드롭할 수 있어요.

  • 그렇지 않으면 존재하지 않는 태그에서 IF EXISTS로 실패하지 않기
-- DROP tag1
ALTER TABLE test DROP TAG tag1;

-- DROP tag1 IF EXISTS
ALTER TABLE test DROP TAG IF EXISTS tag1;

ALTER TABLE ... EXECUTE FAST-FORWARD

다른 브랜치의 조상인 아이스버그 브랜치는 다른 브랜치의 상태로 fast-forward할 수 있어요.

-- This fast-forwards the branch1 to the state of main branch of the Iceberg table.
ALTER table test EXECUTE FAST-FORWARD 'branch1' 'main';

-- This fast-forwards the branch1 to the state of branch2.
ALTER table test EXECUTE FAST-FORWARD 'branch1' 'branch2';

ALTER TABLE ... EXECUTE CHERRY-PICK

스냅샷의 체리픽에는 스냅샷의 ID가 필요해요. 현재로서는 아이스버그 테이블의 main 브랜치에서만 스냅샷 체리픽이 지원돼요.

 ALTER table test EXECUTE CHERRY-PICK 8602659039622823857;

TRUNCATE TABLE

다음 명령은 아이스버그 테이블을 잘라내요.

TRUNCATE TABLE t;

TRUNCATE TABLE ... PARTITION

다음 명령은 아이스버그 테이블의 파티션을 잘라내요.

TRUNCATE TABLE orders PARTITION (customer_id = 1, first_name = 'John');

파티션 스펙은 identity 파티션 컬럼만 지원해요. 파티션 스펙의 변환 컬럼은 지원되지 않아요.

DROP TABLE

테이블은 DROP TABLE 명령으로 드롭할 수 있어요.

DROP TABLE [IF EXISTS] table_name [PURGE];

METADATA LOCATION

새 경로가 정확히 같은 메타데이터 json을 포함할 때만 메타데이터 위치(스냅샷 위치)를 변경할 수 있어요. 이는 테이블을 아이스버그로 마이그레이션한 후에만 수행할 수 있고, 두 연산은 한 단계로 수행할 수 없어요.

ALTER TABLE t set TBLPROPERTIES ('metadata_location'='<path>/hivemetadata/00003-a1ada2b8-fc86-4b5b-8c91-400b6b46d0f2.metadata.json');

DML 명령 (DML Commands)

SELECT

Select 문은 하이브에서 아이스버그 테이블에서도 동일하게 동작해요. 컴파일과 실행에서 아이스버그가 하이브보다 나은 점을 보게 될 거예요.

  • 파일 시스템 목록 나열 없음 - 특히 S3 같은 블랍 스토어에서 중요
  • 메타스토어에서 파티션 목록 없음
  • 고급 파티션 필터링 - 파티션 키를 계산할 수 있을 때 쿼리에 필요하지 않음
  • 일반 하이브 테이블보다 더 많은 수의 파티션 처리 가능

아이스버그 Hive 읽기 지원의 주요 특징은 다음과 같아요.

  1. 조건 푸시다운(Predicate pushdown): Hive SQL WHERE 절의 푸시다운이 구현되어 이 필터가 Iceberg TableScan 수준과 Parquet·ORC Reader 모두에서 사용돼요.
  2. 컬럼 프로젝션(Column projection): Hive SQL SELECT 절의 컬럼이 아이스버그 리더로 프로젝션되어 읽는 컬럼 수를 줄여요.
  3. Hive 쿼리 엔진: Hive 4.x에서 Tez 쿼리 실행 엔진이 지원돼요.

일부 고급/거의 사용되지 않는 최적화는 아이스버그 테이블에 아직 구현되지 않았으므로 개별 쿼리를 확인해야 해요. 또한 현재 MetaStore에 저장된 통계가 쿼리 계획에 사용돼요. 이는 향후에 개선할 계획이에요.

Hive 4는 테이블 수준 select 연산과 비슷하게 동작하는 브랜치에 대한 select 연산을 지원해요. 다만 브랜치는 다음과 같이 제공되어야 해요.

-- Branches should be specified as <database_name>.<table_name>.branch_<branch_name>
SELECT * FROM default.test.branch_branch1;

INSERT INTO

Hive는 표준 단일 테이블 INSERT INTO 연산을 지원해요.

INSERT INTO table_a
VALUES ('a', 1);
INSERT INTO table_a
SELECT...;

다중 테이블 삽입도 지원되지만 원자적이지 않아요. 커밋은 한 번에 하나의 테이블로 발생해요. 커밋 과정 동안 부분 변경이 보일 수 있고, 실패는 부분 변경이 커밋된 채 남길 수 있어요. 단일 테이블 내 변경은 원자적으로 유지돼요.

브랜치에 대한 insert-into 연산도 테이블 수준 select 연산과 비슷하게 동작해요. 다만 브랜치는 다음과 같이 제공되어야 해요.

-- Branches should be specified as <database_name>.<table_name>.branch_<branch_name>
INSERT INTO default.test.branch_branch1
VALUES ('a', 1);
INSERT INTO default.test.branch_branch1
SELECT...;

Hive SQL에서 한 번에 여러 테이블에 삽입하는 예시는 다음과 같아요.

FROM customers
   INSERT INTO target1 SELECT customer_id, first_name
   INSERT INTO target2 SELECT last_name, customer_id;

INSERT INTO ... PARTITION

Hive 4는 파티션 수준 INSERT INTO 연산을 지원해요.

INSERT INTO table_a PARTITION (customer_id = 1, first_name = 'John')
VALUES (1,2);
INSERT INTO table_a PARTITION (customer_id = 1, first_name = 'John')
SELECT...;

파티션 스펙은 identity 파티션 컬럼만 지원해요. 파티션 스펙의 변환 컬럼은 지원되지 않아요.

INSERT OVERWRITE

INSERT OVERWRITE는 테이블의 데이터를 쿼리 결과로 교체할 수 있어요. Overwrite는 아이스버그 테이블에서 원자적 연산이에요. 비파티션 테이블의 경우 테이블 내용이 항상 제거돼요. 파티션 테이블의 경우 SELECT 쿼리가 만든 행을 가진 파티션이 교체돼요.

INSERT OVERWRITE TABLE target SELECT * FROM source;

INSERT OVERWRITE ... PARTITION

Hive 4는 파티션 수준 INSERT OVERWRITE 연산을 지원해요.

INSERT OVERWRITE TABLE target PARTITION (customer_id = 1, first_name = 'John') SELECT * FROM source;

파티션 스펙은 identity 파티션 컬럼만 지원해요. 파티션 스펙의 변환 컬럼은 지원되지 않아요.

DELETE FROM

Hive 4는 테이블에서 데이터를 제거하는 DELETE FROM 쿼리를 지원해요.

Delete 쿼리는 삭제할 행을 일치시키는 필터를 받아요.

DELETE FROM target WHERE id > 1 AND id < 10;

DELETE FROM target WHERE id IN (SELECT id FROM source);

DELETE FROM target WHERE id IN (SELECT min(customer_id) FROM source);

삭제 필터가 테이블의 전체 파티션과 일치하면 아이스버그는 메타데이터 전용 삭제를 수행해요. 필터가 테이블의 개별 행과 일치하면 아이스버그는 영향받은 데이터 파일만 재작성해요.

UPDATE

Hive 4는 업데이트할 행을 일치시키는 필터를 받는 UPDATE 쿼리를 지원해요.

UPDATE target SET first_name = 'Raj' WHERE id > 1 AND id < 10;

UPDATE target SET first_name = 'Raj' WHERE id IN (SELECT id FROM source);

UPDATE target SET first_name = 'Raj' WHERE id IN (SELECT min(customer_id) FROM source);

들어오는 데이터에 기반한 더 복잡한 행 수준 업데이트는 MERGE INTO 섹션을 참고해주세요.

MERGE INTO

Hive 4는 행 수준 업데이트를 표현할 수 있는 MERGE INTO 쿼리 지원을 추가했어요.

MERGE INTO는 target 테이블이라고 부르는 테이블을, source라고 부르는 다른 쿼리의 업데이트 집합을 사용해서 업데이트해요. target 테이블의 행에 대한 업데이트는 조인 조건 같은 ON 절을 사용해서 찾아요.

MERGE INTO target AS t        -- a target table
USING source s                -- the source updates
ON t.id = s.id                -- condition to find updates for target rows
WHEN ...                      -- updates

target 테이블의 행에 대한 업데이트는 WHEN MATCHED ... THEN ...으로 나열돼요. 각 매치가 언제 적용돼야 하는지를 결정하는 조건으로 여러 MATCHED 절을 추가할 수 있어요. 첫 번째로 일치하는 표현식이 사용돼요.

WHEN MATCHED AND s.op = 'delete' THEN DELETE
WHEN MATCHED AND t.count IS NULL AND s.op = 'increment' THEN UPDATE SET t.count = 0
WHEN MATCHED AND s.op = 'increment' THEN UPDATE SET t.count = t.count + 1

일치하지 않는 소스 행(업데이트)은 삽입할 수 있어요.

WHEN NOT MATCHED THEN INSERT VALUES (s.a, s.b, s.c)

소스 데이터의 레코드 하나만 target 테이블의 주어진 행을 업데이트할 수 있고, 그렇지 않으면 오류가 발생해요.

메타데이터 테이블 쿼리 (QUERYING METADATA TABLES)

Hive는 아이스버그 메타데이터 테이블 쿼리를 지원해요. 이 테이블들은 일반 Hive 테이블로 사용될 수 있으므로 프로젝션/조인/필터 등을 사용할 수 있어요. 메타데이터 테이블을 참조하려면 테이블의 전체 이름을 사용해야 해요.

현재 하이브에서 사용 가능한 메타데이터 테이블은 다음과 같아요.

  • all_data_files
  • all_delete_files
  • all_entries
  • all_files
  • all_manifests
  • data_files
  • delete_files
  • entries
  • files
  • history
  • manifests
  • metadata_log_entries
  • partitions
  • refs
  • snapshots
SELECT * FROM default.table_a.files;

타임 트래블 (TIMETRAVEL)

Hive는 스냅샷 ID 기반과 시간 기반 타임 트래블 쿼리를 지원해요. 이런 뷰에 대해 프로젝션/조인/필터 등을 사용할 수 있어요. 이 함수는 다음 구문으로 사용할 수 있어요.

SELECT * FROM table_a FOR SYSTEM_TIME AS OF '2021-08-09 10:35:57';
SELECT * FROM table_a FOR SYSTEM_VERSION AS OF 1234567;

하이브에서 ALTER TABLE 쿼리로 아이스버그 테이블의 스냅샷을 만료시킬 수 있어요. 더 이상 필요 없는 데이터 파일을 삭제하고 테이블 메타데이터 크기를 줄이려면 스냅샷을 주기적으로 만료시켜야 해요.

하이브에서 아이스버그 테이블에 대한 각 쓰기는 테이블의 새 스냅샷(또는 버전)을 만들어요. 스냅샷은 타임 트래블 쿼리에 사용할 수 있고, 테이블은 유효한 스냅샷으로 롤백할 수도 있어요. 스냅샷은 expire_snapshots 연산으로 만료될 때까지 누적돼요.

다음 타임스탬프를 가진 스냅샷을 만료시키는 쿼리를 입력해요.

ALTER TABLE test_table EXECUTE expire_snapshots('2021-12-09 05:39:18.689000000');

고아 파일 삭제 (DELETE ORPHAN-FILES)

아이스버그 테이블의 어떤 메타데이터 파일에서도 참조되지 않아 "고아(orphaned)"로 간주할 수 있는 파일을 제거하는 데 사용돼요. 이 함수는 다음 구문으로 사용할 수 있어요.

ALTER TABLE table_a EXECUTE DELETE ORPHAN-FILES;
ALTER TABLE table_a EXECUTE DELETE ORPHAN-FILES OLDER THAN ('2021-12-09 05:39:18.689000000');

타입 호환성 (Type compatibility)

Hive와 아이스버그는 서로 다른 타입 집합을 지원해요. 아이스버그는 자동으로 타입 변환을 수행할 수 있지만 모든 조합에 대해서는 아니므로, 테이블의 컬럼 타입을 설계하기 전에 아이스버그의 타입 변환을 이해하는 것이 좋아요. Hadoop 구성으로 자동 변환을 활성화할 수 있어요 (기본적으로 활성화되지 않음):

구성 키 기본값 설명
iceberg.mr.schema.auto.conversion false Hive가 타입 자동 변환을 수행해야 하는지 여부

Hive 타입을 아이스버그 타입으로 (Hive type to Iceberg type)

이 타입 변환 표는 Hive 타입이 아이스버그 타입으로 어떻게 변환되는지 설명해요. 이 변환은 아이스버그 테이블 생성과 Hive를 통한 아이스버그 테이블 쓰기 모두에 적용돼요.

Hive Iceberg 참고
boolean boolean
short integer auto-conversion
byte integer auto-conversion
integer integer
long long
float float
double double
date date
timestamp timestamp without timezone
timestamplocaltz timestamp with timezone Hive 3 전용
interval_year_month 지원되지 않음
interval_day_time 지원되지 않음
char string auto-conversion
varchar string auto-conversion
string string
binary binary
decimal decimal
struct struct
list list
map map
union 지원되지 않음

테이블 롤백 (Table rollback)

아이스버그 테이블 데이터를 더 오래된 테이블 스냅샷의 상태로 롤백해요.

특정 타임스탬프 이전의 마지막 스냅샷으로 롤백:

ALTER TABLE ice_t EXECUTE ROLLBACK('2022-05-12 00:00:00')

특정 스냅샷 ID로 롤백:

ALTER TABLE ice_t EXECUTE ROLLBACK(1111);

컴팩션 (Compaction)

Hive 4는 다음 명령으로 아이스버그 테이블의 전체 테이블 컴팩션을 지원해요.

-- Using the ALTER TABLE ... COMPACT syntax
ALTER TABLE t COMPACT 'major';

-- Using the OPTIMIZE TABLE ... REWRITE DATA syntax
OPTIMIZE TABLE t REWRITE DATA;

두 구문 모두 아이스버그 테이블에서 전체 테이블 컴팩션을 수행하는 데 같은 효과가 있어요.

더 알아보기 (Learn more)