Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
0285cac
add V2DeleteHandling enum for iceberg v2 delete file support
Shekharrajak Apr 6, 2026
3cd0903
add iceberg-data dependency and promote iceberg-parquet to compile scope
Shekharrajak Apr 6, 2026
282eb5b
implement IcebergRecordConverter for iceberg Record to Druid map conv…
Shekharrajak Apr 6, 2026
24d8178
implement streaming IcebergNativeRecordReader with v2 delete support
Shekharrajak Apr 6, 2026
aaf7527
add FileScanResult and extractFileScanTasks to IcebergCatalog for v2 …
Shekharrajak Apr 6, 2026
6ae9a92
wire v2DeleteHandling into IcebergInputSource with native reader routing
Shekharrajak Apr 6, 2026
75a386a
add unit tests for IcebergRecordConverter and V2DeleteHandling
Shekharrajak Apr 6, 2026
bfc327b
fix compilation: use public Iceberg APIs and correct Druid method sig…
Shekharrajak Apr 6, 2026
67361c2
fix test compilation and all test failures for v2 delete handling
Shekharrajak Apr 6, 2026
356b75e
cleanup temporary settings file
Shekharrajak Apr 6, 2026
0213225
remove V2DeleteHandling config and add auto-detect routing in Iceberg…
Shekharrajak Apr 6, 2026
78a3da8
add DeleteFileInfo POJO for serializable delete file metadata
Shekharrajak Apr 6, 2026
097513a
add IcebergFileTaskInputSource for per-task serializable v2 input source
Shekharrajak Apr 6, 2026
79c1b06
rewrite IcebergNativeRecordReader with manual positional and equality…
Shekharrajak Apr 6, 2026
fc2ff15
add CompositeInputSourceReader for multi-task v2 reading in IcebergIn…
Shekharrajak Apr 6, 2026
01f4d54
register IcebergFileTaskInputSource in IcebergDruidModule
Shekharrajak Apr 6, 2026
708daed
update all tests for auto-detect v2 architecture without V2DeleteHand…
Shekharrajak Apr 6, 2026
6c78dd9
fix missing Iterator import in IcebergInputSource
Shekharrajak Apr 6, 2026
8745f71
docs: add iceberg v2 delete file support documentation
Shekharrajak Apr 6, 2026
d3cffe0
fix checkstyle, strict compilation, and double-brace initialization e…
Shekharrajak Apr 6, 2026
48eb2f5
add v2 table creation overload to IcebergRestCatalogResource
Shekharrajak Apr 6, 2026
569bf75
add IcebergV2DeleteIngestionTest with equality, positional, mixed, an…
Shekharrajak Apr 6, 2026
9591eb1
fix IT compilation: correct GenericParquetWriter method reference and…
Shekharrajak Apr 6, 2026
983e683
fix dependency:analyze by scoping iceberg-data as runtime and adding …
Shekharrajak Apr 6, 2026
3a72883
remove stray processing/.factorypath IDE artifact
Shekharrajak Apr 6, 2026
09f23b3
remove all stray .factorypath IDE artifacts from tracking
Shekharrajak Apr 6, 2026
83767c3
Iceberg: reject unsupported delete file content types explicitly
Shekharrajak May 17, 2026
25edf28
Iceberg: route v2 reader I/O through catalog FileIO instead of empty …
Shekharrajak May 17, 2026
f472635
Iceberg: test positional delete file scoping across multiple data files
Shekharrajak May 17, 2026
2083811
Iceberg: test equality delete with NULL value matches NULL rows
Shekharrajak May 17, 2026
6717a9e
Iceberg: extract delete-file mapping into testable helper with reject…
Shekharrajak May 17, 2026
2942e5f
Iceberg: test partitioned v2 table delete scoping
Shekharrajak May 17, 2026
80b2c8a
Iceberg: make v2 path splittable so MSQ and parallel batch ingest rows
Shekharrajak May 17, 2026
0d5cb9e
Iceberg: make withSplit and getSplitHintSpecOrDefault self-loading
Shekharrajak May 17, 2026
dacbb05
Fix missing @Override on setup/tearDown in IcebergV2DeleteIngestionTest
Shekharrajak May 17, 2026
0b8775e
Call super.setup/tearDown in IcebergV2DeleteIngestionTest to start cl…
Shekharrajak May 17, 2026
3af8a59
Fix unclosed Iceberg writer before toDataFile/toDeleteFile calls
Shekharrajak May 18, 2026
fa883f6
Fix GenericParquetWriter::buildWriter -> ::create for Iceberg 1.10
Shekharrajak May 18, 2026
72d44bd
Guard non-Parquet Iceberg formats with UnsupportedOperationException …
Shekharrajak May 18, 2026
a56c177
Fix MSQ ClassCastException, null StructLike, and ORDER BY issues in I…
Shekharrajak May 19, 2026
bbcb23f
Fix positional delete writer: use withSpec instead of forTable to avo…
Shekharrajak May 20, 2026
604e496
Guard delete file formats independently and document Parquet-only lim…
Shekharrajak May 20, 2026
386a37f
Fix DeleteFileInfo constructor calls in V2DeleteHandlingTest after ad…
Shekharrajak May 20, 2026
5ecc28c
fix(iceberg): promote iceberg-data to compile scope and drop stale un…
Shekharrajak May 27, 2026
5962d62
fix(iceberg): plumb catalog Hadoop Configuration through to V2 native…
Shekharrajak May 27, 2026
d935f2a
revert: undo Configuration plumbing through IcebergFileTaskInputSourc…
Shekharrajak May 31, 2026
db5ca12
iceberg: expose getHadoopConfigOverrides on catalog SPI
Shekharrajak May 31, 2026
d8298f5
iceberg: carry hadoopConfigOverrides on FileScanResult and v2 input s…
Shekharrajak May 31, 2026
fe61dd5
iceberg: inject @HiveConf into v2 input source and build effective co…
Shekharrajak May 31, 2026
477db74
iceberg: add v2 input source serde and override-prop tests
Shekharrajak May 31, 2026
e9b3b82
iceberg: exclude transitive orc-core from iceberg-data to avoid ORC c…
Shekharrajak Jun 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions docs/development/extensions-contrib/iceberg.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ Iceberg refers to these metastores as catalogs. The Iceberg extension lets you c

For a given catalog, Iceberg input source reads the table name from the catalog, applies the filters, and extracts all the underlying live data files up to the latest snapshot.
The data files can be in Parquet, ORC, or Avro formats. The data files typically reside in a warehouse location, which can be in HDFS, S3, or the local filesystem.

:::note
For Iceberg v1 tables (no delete files), all three formats are supported via the configured `warehouseSource`. For Iceberg v2 tables with delete files, only **Parquet** is currently supported for both data files and delete files. Attempting to ingest an ORC or Avro v2 table results in an `UnsupportedOperationException`. See [#19472](https://github.com/apache/druid/issues/19472) for planned ORC and Avro support.
:::

The `druid-iceberg-extensions` extension relies on the existing input source connectors in Druid to read the data files from the warehouse. Therefore, the Iceberg input source can be considered as an intermediate input source, which provides the file paths for other input source implementations.

## Hive metastore catalog
Expand Down Expand Up @@ -194,6 +199,66 @@ Example:

When `residualFilterMode` is set to `fail` and a residual filter is detected, the job will fail with an error message indicating which filter expression produced the residual. This helps ensure data quality by preventing unintended rows from being ingested.

## Iceberg v2 delete file support

Iceberg v2 tables support row-level deletes through two types of delete files:

| File type | Content | Purpose |
|-----------|---------|---------|
| Positional delete file | `(file_path, row_position)` pairs | Deletes the row at a specific position in a data file |
| Equality delete file | Column value sets | Deletes any row where the specified column values match |

The Iceberg extension automatically detects v2 delete files during table scan. No configuration changes are required to existing ingestion specs.

### How it works

When `IcebergInputSource` scans the Iceberg table, it inspects each `FileScanTask` for associated delete files:

- **No delete files (v1 path)**: Data file paths are extracted and delegated to `warehouseSource` for reading. This is the existing behavior and remains unchanged.
- **Delete files detected (v2 path)**: Each task is wrapped in an `IcebergFileTaskInputSource` that carries the data file path, delete file metadata (paths, types, equality field IDs, and format), and the serialized table schema. The `IcebergNativeRecordReader` then applies deletes at read time:
1. Reads positional delete files and builds a set of deleted row positions for the current data file.
2. Reads equality delete files and builds sets of deleted key tuples.
3. Streams the data file and skips any row that is position-deleted or equality-deleted.

:::note
The v2 delete path currently supports only **Parquet** format for both data files and delete files. Each delete file's format is validated independently. An `UnsupportedOperationException` is thrown if a non-Parquet data file or delete file is encountered. See [#19472](https://github.com/apache/druid/issues/19472).
:::
4. Converts surviving Iceberg records to Druid `InputRow` objects.

### Example

Given an Iceberg v2 table with the following snapshots:

```
Snapshot 1 (append): data-001.parquet -> rows: order_id=1, order_id=2, order_id=3
Snapshot 2 (delete): eq-delete-001.parquet -> "delete where order_id = 2"
```

Druid ingests only `order_id=1` and `order_id=3`. The deleted row (`order_id=2`) is excluded automatically.

The ingestion spec is identical to a v1 table -- no additional fields are needed:

```json
{
"type": "iceberg",
"tableName": "orders",
"namespace": "analytics",
"icebergCatalog": {
"type": "rest",
"catalogUri": "http://localhost:8181"
},
"warehouseSource": {
"type": "s3"
}
}
```

### Performance considerations

- Positional delete files are read into an in-memory `Set<Long>` per data file. Memory usage is proportional to the number of deleted positions, not the data file size.
- Equality delete files are read into an in-memory `Set` of key tuples. For tables with very large equality delete files, this may increase memory usage on the ingestion worker.
- A v2-format table that has never had any rows deleted (no delete files) automatically goes through the v1 path with no overhead.

## Known limitations

This section lists the known limitations that apply to the Iceberg extension.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,21 @@ public Table createTable(String namespace, String tableName, Schema schema)
return getClientCatalog().createTable(tableId, schema);
}

/**
* Creates a table with custom properties (e.g., format-version=2 for v2 tables).
*/
public Table createTable(
String namespace,
String tableName,
Schema schema,
org.apache.iceberg.PartitionSpec partitionSpec,
Map<String, String> properties
)
{
final TableIdentifier tableId = TableIdentifier.of(namespace, tableName);
return getClientCatalog().createTable(tableId, schema, partitionSpec, properties);
}

/**
* Drops a table from the REST catalog. Best-effort; ignores errors.
*/
Expand Down
Loading
Loading