Search before asking
Motivation
Paimon's lake writer implements SupportsRecordBatchWrite (landed in #3417/#3418), enabling direct Arrow batch to Parquet writes for append-only tables. This avoids the row-by-row serialization overhead through GenericRecord objects.
The Iceberg lake writer (IcebergLakeWriter) currently writes row-by-row via GenericAppenderFactory, resulting in significantly lower throughput for append-only log table tiering compared to the Paimon path.
Since Fluss uses Arrow as its internal columnar format, and both Iceberg and Parquet have native Arrow support (iceberg-arrow module, parquet-arrow module), we can bridge the Arrow batch directly to Iceberg Parquet files.
Solution
- Make
IcebergLakeWriter implement SupportsRecordBatchWrite
- Create an Arrow batch writer that takes
ArrowBatchData and writes to Iceberg Parquet files
- Only enabled for append-only tables (same restriction as Paimon)
- Preserve Iceberg file metrics tracking for proper table maintenance
Related: #437 (generic arrow-to-parquet issue)
Upstream Issues for True Zero-Copy Path
The current PR (#4048) implements SupportsRecordBatchWrite by reading Arrow vectors and producing GenericRecord objects. This avoids binary log deserialization but still materializes row objects because Iceberg and parquet-java lack columnar write APIs.
Upstream issues filed to enable true zero-copy Arrow-to-Parquet writes:
- apache/parquet-java#3733 — Add
ParquetWriter<VectorSchemaRoot> to the parquet-arrow module. This is the foundational primitive.
- apache/iceberg#17748 — Add
FileAppender<VectorSchemaRoot> to Iceberg's arrow module. Depends on (or works alongside) the parquet-java change.
Once these land, Fluss can replace the IcebergArrowBatchHelper (GenericRecord bridge) with a direct call to Iceberg's vectorized appender.
Anything else?
All necessary primitives exist in upstream Iceberg (iceberg-arrow 1.10.1) and Apache Parquet (parquet-arrow). No upstream changes needed for the initial implementation; upstream changes enable the optimized path.
Willingness to contribute
Search before asking
Motivation
Paimon's lake writer implements
SupportsRecordBatchWrite(landed in #3417/#3418), enabling direct Arrow batch to Parquet writes for append-only tables. This avoids the row-by-row serialization overhead throughGenericRecordobjects.The Iceberg lake writer (
IcebergLakeWriter) currently writes row-by-row viaGenericAppenderFactory, resulting in significantly lower throughput for append-only log table tiering compared to the Paimon path.Since Fluss uses Arrow as its internal columnar format, and both Iceberg and Parquet have native Arrow support (
iceberg-arrowmodule,parquet-arrowmodule), we can bridge the Arrow batch directly to Iceberg Parquet files.Solution
IcebergLakeWriterimplementSupportsRecordBatchWriteArrowBatchDataand writes to Iceberg Parquet filesRelated: #437 (generic arrow-to-parquet issue)
Upstream Issues for True Zero-Copy Path
The current PR (#4048) implements
SupportsRecordBatchWriteby reading Arrow vectors and producingGenericRecordobjects. This avoids binary log deserialization but still materializes row objects because Iceberg and parquet-java lack columnar write APIs.Upstream issues filed to enable true zero-copy Arrow-to-Parquet writes:
ParquetWriter<VectorSchemaRoot>to theparquet-arrowmodule. This is the foundational primitive.FileAppender<VectorSchemaRoot>to Iceberg's arrow module. Depends on (or works alongside) the parquet-java change.Once these land, Fluss can replace the
IcebergArrowBatchHelper(GenericRecord bridge) with a direct call to Iceberg's vectorized appender.Anything else?
All necessary primitives exist in upstream Iceberg (
iceberg-arrow1.10.1) and Apache Parquet (parquet-arrow). No upstream changes needed for the initial implementation; upstream changes enable the optimized path.Willingness to contribute