Introduction
Iceberg provides a catalog interface that requires the implementation of a set of func tions, primarily ones to list existing tables, create tables, drop tables, check whether a table exists, and rename tables.
The primary high-level requirement for a catalog implementation to work as an Iceberg catalog is to map a table path (e.g., db1.table1) to the filepath of the metadata file that has the table’s current state. Not all implementations are suitable for being used in production: only the one that support atomic operations for updating the current metadata pointer should be used to avoid data loss
The examples in here are for Spark (see Apache Iceberg with Spark for setup), but similar concept applies to Apache Iceberg with Flink
Main catalogs
The Hadoop Catalog
The Hadoop Catalog maps the table path to its current metadata file by listing the contents of the table’s metadata directory and choosing the most recently written metadata file based on the timestamp listed for each file in the filesystem. It is not recommended to be used in production for three reasons:
- not all filesystems provide atomic updates
- it can only be used with one warehouse folder
- listing the catalog tables require listing the filesystem
Warehouse folder
A warehouse is essentially a root directory under which multiple Iceberg tables are stored. The Hadoop catalog cannot handle tables that are not under a single folder hierarchy
Tip
Generally, however, engines will write a file called version-hint.txt in the table’s meta‐ data folder containing a single number that the engine/tool then uses to retrieve the indicated metadata file by name—for example, v{n}.metadata.json.
To launch Spark with the Hadoop Catalog, besides the SparkSessionExtensions defined above, the following extra conf are needed:
--conf
spark.sql.catalog.my_catalog1=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.my_catalog1.type=hadoop \
--conf
spark.sql.catalog.my_catalog1.warehouse=<protocol>://<path>The Hive Catalog
The Hive catalog maps a table’s path to its current metadata file by using the location table property in the table’s entry in the Hive Metastore, setting it to the absolute path in the filesystem where the table’s current metadata file can be located. Although it is compatible with many tools, the Hive catalog is often not a good choice for two reasons:
- it requires an external dependency/component
- it doesn’t support multitable transactions
Compared to the Hadoop catalog, to use it one needs to change spark.sql.catalog.catalog_name.type from hadoop to hive and set spark.sql.catalog.catalog_name.uri to a thrift address for the metastore rather than a warehouse
The Glue Catalog
The Glue catalog is fully managed by AWS, reducing operational overhead. However, it still doesn’t support multitable transactions and is very coupled with AWS. To use it, one needs to set additional properties when starting spark
--conf spark.sql.catalog.my_catalog1.warehouse=s3://<path> \
--conf spark.sql.catalog.my_catalog1.catalog-impl=org.apache.ice-
berg.aws.glue.GlueCatalog \
--conf spark.sql.catalog.my_catalog1.io-impl=org.apache.iceberg.aws.s3.S3FileIO \
--conf spark.hadoop.fs.s3a.access.key=$AWS_ACCESS_KEY \
--conf spark.hadoop.fs.s3a.secret.key=$AWS_SECRET_ACCESS_KEYThe Nessie Catalog
With Nessie, a table’s path is mapped to its current metadata file using a table property called metadataLocation stored within the table’s entry in Nessie similarly to what is done with the Hive catalog. Nessie is a great choice:
- it supports multitable transactions
- it provides a Git-like experience to data lakes and enables the concept of “data as code”
The REST Catalog
The service implementing the REST catalog interface can choose to store the mapping of a table’s path to its current metadata file in any way it chooses. It could even store it in one of the other catalogs and provide multitable transactions.
Warning
Not all tools support the REST Catalog, and there is no available implementation. The only existing one is managed and is provided by Tabular
The JDBC Catalog
The JDBC catalog is backed by a relational database such as PostgreSQL or MySQL and is relatively lightweight to operate. However, it doesnt support multitable transactions
Other catalogs
A popular catalog is Snowflake, but also the Unity Catalog
A note on SparkSessionCatalog
The SparkSessionCatalog is a more specialized implementation that wraps around Spark’s built-in session catalog, adding support for Iceberg tables. This could benefit scenarios when you want to use Iceberg tables seamlessly alongside non-Iceberg tables in your Spark session: all the non-Iceberg tables are managed by the built-in Spark catalog, while the tables specific to Iceberg are managed separately through the SparkSessionCatalog
Important
Running create table as select(CTAS) in the context of Apache Iceberg is an atomic operation only when using the SparkCatalog class. If you use the SparkSessionCatalog class, CTAS is supported but is not atomic, which may cause inconsistencies when
Migrations
Migrations can happen in two ways:
- using the Catalog Migrator CLI
- using the Engine, such as Spark
java -jar iceberg-catalog-migrator-cli-0.2.0.jar migrate \
--source-catalog-type GLUE \
--source-catalog-properties warehouse=s3a://bucket/gluecatalog/,io-
impl=org.apache.iceberg.aws.s3.S3FileIO \
--source-catalog-hadoop-conf
fs.s3a.secret.key=$AWS_SECRET_ACCESS_KEY,fs.s3a.access.key=$AWS_ACCESS_KEY_ID \
--target-catalog-type NESSIE \
--target-catalog-properties uri=http://localhost:19120/api/v1,ref=main,ware-
house=s3a://bucket/nessie/,io-impl=org.apache.iceberg.aws.s3.S3FileIO \
--identifiers db1.nomineesThe Migration CLI offers two main commands:
migratewhich effectively will remove the table from the input catalogregisterwhich will have the table registered in both catalogs with update to the table through the new catalog not being reflected in the old catalog
An alternative is to use the engine call to invoke register_table, which effectively means the same table is reigstered in two catalogs, or snapshot, which creates a non-owning registration of the table(i.e. expire_snapshots is not possible)
CALL target_catalog.system.register_table(
'target_catalog.db1.table1',
'/path/to/source_catalog_warehouse/db1/table1/metadata/xxx.json'
)or so:
CALL target_catalog.system.snapshot(
'source_catalog.db1.table1',
'target_catalog.db1.table1'
)