Hello, I’m DocuDroid!
Submitting feedback
Thank you for rating our AI Search!
We would be grateful if you could share your thoughts so we can improve our AI Search for you and other readers.
GitHub

Use PXF Iceberg connector to read and write Iceberg-format data between Greengage DB and Hive Metastore and REST catalogs

Anton Monakov

Apache Iceberg is an open-source data format designed for large analytic tables. It supports SQL commands and enables concurrent read/write operations from multiple query engines including Spark, Trino, Flink, Presto, Hive, and Impala.

PXF Iceberg connector supports the following features:

  • Reading and writing data in Hive Metastore and REST catalogs.

  • Reading data in Parquet, ORC, and Avro formats.

  • Writing data in Parquet format.

  • Reading and writing data to dedicated Iceberg branches and tags.

  • Column projection.

  • Predicate pushdown.

NOTE

For foreign tables, the master commit protocol is supported, which allows for exchanging metadata between executors and the master. Metadata is aggregated from all segments and the write transaction is then finalized via a single HTTP request to the PXF server. To enable the protocol, add the ext_protocol_version option with value v1 to the foreign data wrapper definition.

This topic describes how to configure and use the PXF Iceberg connector for reading and writing Iceberg data stored in the Hive Metastore and REST catalogs by using external and foreign tables and provides practical examples.

Compatibility notes

For correct operation, the PXF Iceberg connector requires Greengage DB 6.31.0 or later and PXF 6.16.0 or later.

For earlier Greengage DB, PXF, and the pxf_fdw extension versions, a compatibility layer is provided, under which working with Iceberg data is possible with several limitations.

PXF version pxf_fdw version Greengage DB version Runtime error when working with Iceberg Iceberg support

Required

Required

Required

No

Yes

Earlier

Earlier

Earlier

No

No

Required

Earlier

Earlier

No

No

Required

Required

Earlier

No

Creating, selecting from, and inserting into Iceberg foreign tables is supported. Master commit protocol is not supported: multiple snapshots are created for different PXF instances

Earlier

Required

Earlier

Yes

Only creating Iceberg foreign tables is supported; selecting from or inserting into foreign tables is not supported. No iceberg protocol is available

Earlier

Required

Required

Yes

Only creating Iceberg foreign tables is supported; selecting from or inserting into foreign tables is not supported. No iceberg protocol is available

Earlier

Earlier

Required

No

No

Configure PXF Iceberg connector

To be able to use the PXF Iceberg connector with external tables, you need to create a server configuration as described in Configure a PXF server in PXF documentation and then synchronize it to the Greengage DB cluster:

  1. Log in to the Greengage DB master host as gpadmin.

  2. Go to the $PXF_BASE/servers directory and create a server configuration directory (for example, named iceberg):

    $ mkdir $PXF_BASE/servers/iceberg
    $ cd $PXF_BASE/servers/iceberg
  3. In the server configuration directory, create an iceberg-site.xml configuration and provide the required configuration depending on the data store used.

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <property>
            <name>iceberg.param.s3.endpoint</name>
            <value>http://minio:9000</value>
            <description>S3 endpoint</description>
        </property>
        <property>
            <name>iceberg.param.s3.path-style-access</name>
            <value>true</value>
            <description>S3 path style access</description>
        </property>
        <property>
            <name>iceberg.param.s3.access-key-id</name>
            <value>admin</value>
            <description>S3 access key id</description>
        </property>
        <property>
            <name>iceberg.param.s3.secret-access-key</name>
            <value>minioadmin</value>
            <description>S3 secret access key</description>
        </property>
        <property>
            <name>iceberg.param.client.region</name>
            <value>us-east-1</value>
            <description>AWS region</description>
        </property>
        <property>
            <name>iceberg.param.uri</name>
            <value>http://iceberg-rest:8181</value>
            <description>Catalog uri</description>
        </property>
        <property>
            <name>iceberg.config.catalog.name</name>
            <value>iceberg_rest_s3</value>
            <description>Catalog name</description>
        </property>
        <property>
            <name>iceberg.config.catalog.type</name>
            <value>REST</value>
            <description>Catalog type</description>
        </property>
    </configuration>
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <property>
            <name>iceberg.param.uri</name>
            <value>thrift://hive-metastore:9083</value>
            <description>Catalog uri</description>
        </property>
        <property>
            <name>iceberg.config.catalog.name</name>
            <value>iceberg_hive</value>
            <description>Catalog name</description>
        </property>
        <property>
            <name>iceberg.config.catalog.type</name>
            <value>HIVE_METASTORE</value>
            <description>Catalog type</description>
        </property>
    </configuration>
  4. Synchronize the server configuration to the Greengage DB cluster hosts:

    $ pxf cluster sync

Server configuration properties

Option Server configuration property Description

uri

iceberg.param.uri

Iceberg catalog URI

catalog_type

iceberg.config.catalog.type

Iceberg catalog type (REST or HIVE_METASTORE)

catalog_name

iceberg.config.catalog.name

Iceberg catalog name

ref

 — 

The name of an Iceberg branch or tag. When reading data, the name of an existing tag or branch must be provided

fragmentSize

 — 

The target size of a fragment in bytes

s3_endpoint

iceberg.param.s3.endpoint

S3 endpoint (for S3 storage)

s3_path_style_access

iceberg.param.s3.path-style-access

S3 path style access (for S3 storage)

s3_access_key_id

iceberg.param.s3.access-key-id

S3 access key id (for S3 storage)

s3_secret_access_key

iceberg.param.s3.secret-access-key

S3 secret access key (for S3 storage)

aws_region

iceberg.param.client.region

AWS region (for S3 storage)

Create an Iceberg foreign data wrapper

To work with Iceberg data using foreign tables, you need to create a foreign data wrapper.

  1. On the Greengage DB master host, list the extensions available for installation:

    SELECT * FROM pg_available_extensions WHERE name LIKE '%pxf_fdw%';

    The output should list pxf_fdw:

         name     | default_version | installed_version |               comment
    
    --------------+-----------------+-------------------+-----------------------------------------
     pxf_fdw      | 1.0             |                   | PXF Foreign Data Wrapper for Greengage
     (1 row)
  2. Create an extension to register the pxf_fdw foreign data wrapper in the database where you plan to use it:

    CREATE EXTENSION pxf_fdw;

    Then, make sure the iceberg_pxf_fdw foreign data wrapper is available:

    SELECT * FROM pg_catalog.pg_foreign_data_wrapper;

    The output should look as follows:

         fdwname     | fdwowner | fdwhandler | fdwvalidator | fdwacl |                  fdwoptions
    -----------------+----------+------------+--------------+--------+-----------------------------------------------
     jdbc_pxf_fdw    |       10 |      24609 |        24610 |        | {protocol=jdbc,"mpp_execute=all segments"}
     hdfs_pxf_fdw    |       10 |      24609 |        24610 |        | {protocol=hdfs,"mpp_execute=all segments"}
     hive_pxf_fdw    |       10 |      24609 |        24610 |        | {protocol=hive,"mpp_execute=all segments"}
     hbase_pxf_fdw   |       10 |      24609 |        24610 |        | {protocol=hbase,"mpp_execute=all segments"}
     s3_pxf_fdw      |       10 |      24609 |        24610 |        | {protocol=s3,"mpp_execute=all segments"}
     gs_pxf_fdw      |       10 |      24609 |        24610 |        | {protocol=gs,"mpp_execute=all segments"}
     adl_pxf_fdw     |       10 |      24609 |        24610 |        | {protocol=adl,"mpp_execute=all segments"}
     wasbs_pxf_fdw   |       10 |      24609 |        24610 |        | {protocol=wasbs,"mpp_execute=all segments"}
     file_pxf_fdw    |       10 |      24609 |        24610 |        | {protocol=file,"mpp_execute=all segments"}
     iceberg_pxf_fdw |       10 |      24609 |        24610 |        | {protocol=iceberg,"mpp_execute=all segments"}
    (10 rows)

Examples

These examples demonstrate how to configure and use the PXF Iceberg connector for reading and writing Iceberg data in the REST and Hive Metastore catalogs by using external and foreign tables.

Prerequisites

To try out the practical examples, connect to the Greengage DB master host as gpadmin using psql as described in Connect to Greengage DB via psql. Then create the customers test database and connect to it:

DROP DATABASE IF EXISTS customers;
CREATE DATABASE customers;
\c customers

To be able to create an external table using the PXF protocol, enable the PXF extension in the database as described in Register PXF in a database in PXF documentation:

CREATE EXTENSION pxf;

To be able to create a foreign table, register the Iceberg foreign data wrapper in the customers database:

CREATE FOREIGN DATA WRAPPER iceberg_pxf_fdw
    HANDLER pxf_fdw_handler
    VALIDATOR pxf_fdw_validator
    OPTIONS (protocol 'iceberg', mpp_execute 'all segments');

Use REST catalog

Create source data

  1. Connect to the Iceberg REST catalog and create a test database:

    CREATE DATABASE IF NOT EXISTS customers;
  2. Create a source data table:

    CREATE TABLE customers.data (
        id INT,
        first_name VARCHAR(20),
        last_name VARCHAR(20)
    );
  3. Populate the created table with sample data:

    INSERT INTO customers.data 
        VALUES (1, 'John', 'Doe'),
               (2, 'Jane', 'Doe');
  4. Query the created table:

    SELECT * FROM customers.data;

    The output should look as follows:

    1       John    Doe
    2       Jane    Doe
    Time taken: 0.26 seconds, Fetched 2 row(s)

Create a readable external table

  1. On the Greengage DB master host, create a readable PXF external table that references the earlier created customers.data Iceberg table. In the LOCATION clause, specify the PXF iceberg profile and the server configuration. In the FORMAT clause, specify pxfwritable_import, which is the built-in custom formatter function for read operations:

    CREATE EXTERNAL TABLE customers_r_rest (
        id INT, 
        first_name TEXT, 
        last_name TEXT
        )
        LOCATION ('pxf://customers.data?PROFILE=iceberg&SERVER=iceberg')
        FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import');
  2. Query the created external table:

    SELECT * FROM customers_r_rest;

    The output should look as follows:

     id | first_name | last_name
    ----+------------+-----------
      1 | John       | Doe
      2 | Jane       | Doe
    (2 rows)

Create a writable external table

  1. On the Greengage DB master host, create a writable PXF external table that references the earlier created customers.data Iceberg table. In the LOCATION clause, specify the PXF iceberg profile and the server configuration. In the FORMAT clause, specify pxfwritable_export, which is the built-in custom formatter function for write operations:

    CREATE WRITABLE EXTERNAL TABLE customers_w_rest (
        id INT, 
        first_name TEXT, 
        last_name TEXT
        )
        LOCATION ('pxf://customers.data?PROFILE=iceberg&SERVER=iceberg')
        FORMAT 'CUSTOM' (FORMATTER='pxfwritable_export');
  2. Insert some data into the created external table:

    INSERT INTO customers_w_rest (
        id,
        first_name,
        last_name
        )
        VALUES (3, 'Bob', 'Brown'),
               (4, 'Jane', 'Smith');
  3. Connect to the Iceberg REST catalog and query the source customers.data table:

    SELECT * FROM customers.data;

    The output should look as follows:

    1       John    Doe
    2       Jane    Doe
    3       Bob     Brown
    4       Jane    Smith
    Time taken: 0.168 seconds, Fetched 4 row(s)

    Then delete the newly inserted rows to revert the table to its initial state:

    DELETE FROM customers.data WHERE id IN (3,4);

Create a foreign table

  1. On the Greengage DB master host, create a foreign server that uses the iceberg_pxf_fdw foreign data wrapper and points to the REST catalog:

    CREATE SERVER iceberg_rest_server
        FOREIGN DATA WRAPPER iceberg_pxf_fdw
        OPTIONS (uri 'http://iceberg-rest:8181');
  2. Create a user mapping that will handle authentication on the Iceberg REST server. In the SERVER clause, specify the earlier created iceberg_rest_server server; in the OPTIONS clause, provide the authentication parameters (s3_access_key_id and s3_secret_access_key):

    CREATE USER MAPPING FOR CURRENT_USER 
        SERVER iceberg_rest_server
        OPTIONS (s3_access_key_id 'admin', 
                 s3_secret_access_key 'password');
  3. Create the foreign table whose structure matches the one of the customers.data table initially created in the REST catalog. In the SERVER clause, specify the earlier created iceberg_rest_server server; in the OPTIONS clause, provide the name of the earlier created customers.data table:

    CREATE FOREIGN TABLE customers_f_rest (
        id INT,
        first_name TEXT,
        last_name TEXT
        )
        SERVER iceberg_rest_server
        OPTIONS (resource 'customers.data');
  4. Query the created foreign table:

    SELECT * FROM customers_f_rest;

    The output should look as follows:

     id | first_name | last_name
    ----+------------+-----------
      1 | John       | Doe
      2 | Jane       | Doe
    (2 rows)
  5. Insert some data into the created foreign table:

    INSERT INTO customers_f_rest (
        id,
        first_name,
        last_name
        )
        VALUES (3, 'Bob', 'Brown'),
               (4, 'Jane', 'Smith');
  6. Query the foreign table again:

    SELECT * FROM customers_f_rest;

    The output should look as follows:

     id | first_name | last_name
    ----+------------+-----------
      1 | John       | Doe
      2 | Jane       | Doe
      3 | Bob        | Brown
      4 | Jane       | Smith
    (4 rows)
  7. Connect to the Iceberg REST catalog and query the source customers.data table:

    SELECT * FROM customers.data;

    The output should look as follows:

    1       John    Doe
    2       Jane    Doe
    3       Bob     Brown
    4       Jane    Smith
    Time taken: 0.194 seconds, Fetched 4 row(s)

    Then delete the newly inserted rows to revert the table to its initial state:

    DELETE FROM customers.data WHERE id IN (3,4);

Use Hive Metastore catalog

Create source data

  1. On the HiveClient host, launch the Hive command line:

    $ hive
  2. Create the customers Hive table in the default database to store the sample dataset. The STORED BY ICEBERG clause instructs Hive to create the table in the Iceberg format:

    CREATE TABLE customers (
        id INT,
        first_name STRING,
        last_name STRING 
        )
        STORED BY ICEBERG;
  3. Populate the created table with sample data:

    INSERT INTO customers (
        id,
        first_name,
        last_name
        )
        VALUES (1, 'John', 'Doe'),
               (2, 'Jane', 'Doe');
  4. Query the customers Hive table to verify that the data was loaded correctly:

    SELECT * FROM customers;

    The output should look as follows:

    +---------------+-----------------------+----------------------+
    | customers.id  | customers.first_name  | customers.last_name  |
    +---------------+-----------------------+----------------------+
    | 1             | John                  | Doe                  |
    | 2             | Jane                  | Doe                  |
    +---------------+-----------------------+----------------------+
    2 rows selected (0.171 seconds)

Create a readable external table

  1. On the Greengage DB master host, create a readable PXF external table that references the earlier created default.customers Iceberg table. In the LOCATION clause, specify the PXF iceberg profile and the server configuration. In the FORMAT clause, specify pxfwritable_import, which is the built-in custom formatter function for read operations:

    CREATE EXTERNAL TABLE customers_r_hive (
        id INT, 
        first_name TEXT, 
        last_name TEXT
        )
        LOCATION ('pxf://default.customers?PROFILE=iceberg&SERVER=iceberg')
        FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import');
  2. Query the created external table:

    SELECT * FROM customers_r_hive;

    The output should look as follows:

     id | first_name | last_name
    ----+------------+-----------
      1 | John       | Doe
      2 | Jane       | Doe
    (2 rows)

Create a writable external table

  1. On the Greengage DB master host, create a writable PXF external table that references the earlier created default.customers Iceberg table. In the LOCATION clause, specify the PXF iceberg profile and the server configuration. In the FORMAT clause, specify pxfwritable_export, which is the built-in custom formatter function for write operations:

    CREATE WRITABLE EXTERNAL TABLE customers_w_hive (
        id INT, 
        first_name TEXT, 
        last_name TEXT
        )
        LOCATION ('pxf://default.customers?PROFILE=iceberg&SERVER=iceberg')
        FORMAT 'CUSTOM' (FORMATTER='pxfwritable_export');
  2. Populate the created table with sample data:

    INSERT INTO customers_w_hive (
        id,
        first_name,
        last_name
        )
        VALUES (3, 'Bob', 'Brown'),
               (4, 'Jane', 'Smith');
  3. On the HiveClient host, query the customers Iceberg table:

    SELECT * FROM customers;

    The output should look as follows:

    +---------------+-----------------------+----------------------+
    | customers.id  | customers.first_name  | customers.last_name  |
    +---------------+-----------------------+----------------------+
    | 1             | John                  | Doe                  |
    | 2             | Jane                  | Doe                  |
    | 3             | Bob                   | Brown                |
    | 4             | Jane                  | Smith                |
    +---------------+-----------------------+----------------------+
    4 rows selected (0.371 seconds)

    Then delete the newly inserted rows to revert the table to its initial state:

    DELETE FROM customers WHERE id IN (3,4);

Create a foreign table

  1. On the Greengage DB master host, create a foreign server that uses the iceberg_pxf_fdw foreign data wrapper and points to the Hive Metastore catalog. In the OPTIONS clause, set the catalog_type to HIVE_METASTORE and provide the URI of the Hive Metastore server and the name of the Iceberg Hive Metastore catalog:

    CREATE SERVER iceberg_hive_server
        FOREIGN DATA WRAPPER iceberg_pxf_fdw
        OPTIONS (catalog_type 'HIVE_METASTORE', 
                 uri 'thrift://hive-metastore:9083', 
                 catalog_name 'iceberg_hive');
  2. Create a user mapping that will handle authentication on the Iceberg Hive Metastore server. In the SERVER clause, specify the earlier created iceberg_hive_server server:

    CREATE USER MAPPING FOR CURRENT_USER
        SERVER iceberg_hive_server;
  3. Create the foreign table whose structure matches the one of the default.customers table initially created in the Hive Metastore catalog. In the SERVER clause, specify the earlier created iceberg_hive_server server; in the OPTIONS clause, provide the name of the earlier created customers table:

    CREATE FOREIGN TABLE customers_f_hive (
        id INT, 
        first_name TEXT, 
        last_name TEXT
        )
        SERVER iceberg_hive_server
        OPTIONS (resource 'default.customers');
  4. Query the created foreign table:

    SELECT * FROM customers_f_hive;

    The output should look as follows:

     id | first_name | last_name
    ----+------------+-----------
      1 | John       | Doe
      2 | Jane       | Doe
    (2 rows)
  5. Insert some data into the created foreign table:

    INSERT INTO customers_f_hive (
        id,
        first_name,
        last_name
        )
        VALUES (3, 'Bob', 'Brown'),
               (4, 'Jane', 'Smith');
  6. On the HiveClient host, query the customers table:

    SELECT * FROM customers;

    The output should look as follows:

    +---------------+-----------------------+----------------------+
    | customers.id  | customers.first_name  | customers.last_name  |
    +---------------+-----------------------+----------------------+
    | 1             | John                  | Doe                  |
    | 2             | Jane                  | Doe                  |
    | 3             | Bob                   | Brown                |
    | 4             | Jane                  | Smith                |
    +---------------+-----------------------+----------------------+
    4 rows selected (0.132 seconds)

    Then delete the newly inserted rows to revert the table to its initial state:

    DELETE FROM customers WHERE id IN (3,4);