본문 바로가기
Data Engineering

DuckDB를 사용해서 Iceberg 테이블에 쿼리 실행하기

by 홍띠 2024. 9. 15.

Iceberg테이블을 Glue Catalog로 관리하면서 사용하고 있는데, 해당 테이블에 쿼리를 실행하고자 해서 방법을 찾아봤다. 테이블의 용량이 크지 않아 스파크를 사용하고 있지 않다보니, Iceberg 테이블 쿼리에 많이 사용되는 Spark SQL 사용이 어려웠다. 이에 대한 대안으로 DuckDB를 사용하는 방법을 발견해서 적용해보았다.


DuckDB를 사용해서 Iceberg 테이블에 쿼리를 하는 방안으로 2가지를 찾았다.

  1. DuckDB 라이브러리에서 Iceberg Extension을 설치해서 바로 테이블에 쿼리 실행
  2. PyIceberg로 테이블을 먼저 로드해서 이를 DuckDB에 연결 후 쿼리 실행

두가지 방법 모두 시도해 본 결과 2번 방법을 채택해서 사용하기로 했다. 각 방법의 상세 내용을 아래에 기록하고자 한다.

 

1. DuckDB 라이브러리에서 Iceberg Extension을 설치해서 바로 테이블에 쿼리 실행

DuckDB Connection 생성

import duckdb

duckdb_conn = duckdb.connect()

 

S3에 저장된 Iceberg 테이블에 쿼리를 실행하기 위한 DuckDB Extension 설치

duckdb_conn.execute(
    """
    INSTALL httpfs;
    INSTALL iceberg;
    INSTALL aws;
    """
)

 

S3에 접근하기위한 Credential 설정

-> 아래 설정으로는 기본 AWS SDK 설정을 가져옴

duckdb_conn.execute(
    """
    CREATE SECRET (
    TYPE S3,
    PROVIDER CREDENTIAL_CHAIN);
    """
)

 

Iceberg 테이블에 Select 문 실행 (아마도 HDFS Catalog 사용시에만 적용 가능할듯)

iceberg_table = duckdb_conn.execute(
    f"""
    SELECT *
    FROM iceberg_scan('s3://ICEBERG/TABLE/PATH');
    """
)

# 쿼리 결과 확인
iceberg_table.fetchall()

 

위 방법으로 하면 간단하게 테이블 조회가 가능하다.

그런데, Glue Catalog를 활용해서 Iceberg 테이블을 관리하는 경우에는 아래의 이유 때문에 위 방법으로 조회가 불가능하다..!!!

  • DuckDB의 Iceberg extension은 version-hint.text(HDFS Catalog에 해당)을 탐색해서 최신정보의 메타데이터를 불러오는데, Glue catalog를 사용하면 이 version-hint 파일이 따로 생성되지 않음
  • version-hint.text 파일이 없는경우 정확한 메타데이터 파일 경로를 지정하면 됨. - 가장 최신의 메타데이터를 가져오는 방법(custom library 등) 추가로 필요

위의 설명대로 Glue catalog는 version-hint.text 을 생성하지 않기 때문에 DuckDB에서 조회하는 정확한 메타데이터 파일 경로를 지정해야 하는데, 테이블에 변화가 생기면 메타데이터 파일도 변경되기 때문에 가장 최신의 메타데이터 파일을 계속 확인해야하는 불편함이 있다.

메타데이터 경로를 정확하게 지정하면 아래와 같이 쿼리 실행이 가능하다.

iceberg_table = duckdb_conn.execute(
    f"""
    SELECT *
    FROM iceberg_scan('s3://ICEBERG/TABLE/PATH/metadata/00001-sdffsg-babe-4305-82d2-c6a9983c02f6.metadata.json');
    """
)

# 쿼리 결과 확인
iceberg_table.fetchall()

 

최신 메타데이터 파일을 계속 확인해야 하는 번거로움 때문에 해당 방법은 사용하지 않기로 했다.

2. PyIceberg로 테이블을 먼저 로드해서 이를 DuckDB에 연결 후 쿼리 실행

Catalog 설정

from pyiceberg.catalog.glue import GlueCatalog

catalog = GlueCatalog(
    name='bizstr-crm-bronze',
    **{
        "region_name": "ap-northeast-2",
        "uri": "https://glue.ap-northeast-2.amazonaws.com",
        "warehouse": "s3://ICEBERG/PATH",
    }
)

 

Iceberg Table 불러오기

iceberg_table = catalog.load_table(identifier=(DB_NAME, "test_table"))

 

불러온 테이블은 DuckDB Connection에 스캔

duckdb_conn = duckdb.connect()
iceberg_table.scan().to_duckdb(table_name="test_table", connection=duckdb_conn)

 

쿼리 실행

# 테이블 확인
duckdb_conn.sql(
    "SHOW TABLES;"
)

# 쿼리 실행
rel = duckdb_conn.sql(
    f"""
        SELECT *
        FROM test_table
    """
)

# 결과 확인
rel.show()

 

 

두가지 방법을 모두 테스트해본 결과 Glue Catalog + Iceberg 조합을 사용하는 나의 경우에는 2번 방법이 훨씬 간편하게 사용이 가능해서 2번 방법을 결과적으로 사용하기로 했다.