Repository navigation
Conversation
…lters With iceberg.dynamic_filter_pruning_enabled, file listing keeps each file's manifest statistics for the projected columns, and the file pruner turns them into inexact per-file min/max so files whose bounds can't match the scan's dynamic filters are skipped before opening, also on unpartitioned tables.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on #9; review that first.
What and why
With
iceberg.dynamic_filter_pruning_enabledon, the scan already skips whole data files before opening them, but only by their identity partition values. A file without useful partition values, for example any file of an unpartitioned table, was never skipped, even when its column values clearly can't match the dynamic filter. On the unpartitioned taxi table every data file was read (9 → 9).This change also uses each file's per-column lower/upper bounds from its manifest entry, so such files are skipped too.
How statistics are requested, and their cost
TableScanBuilder::with_column_stats(names), in both places files are listed: the lazy work-unit feed (lazy/work_unit_feed.rs, at execution time) and eager planning (table_provider/scan.rs).column_stats_columns). These are the only columns a filter on the scan output can reference; metadata and nested columns have no statistics and would make the scan fail to build.How they reach workers
Tasks travel as
rmp_serdenamed-struct encodings of iceberg-rust'sFileScanTask, in both the lazy feed'sSerializedFileScanTaskand the eager codec's assigned files. TheFileScanTaskserde in the iceberg-rust revision we depend on already includescolumn_stats(with its bounds), so no change to it was needed. A new unit test (column_stats_survive_serialization) round-trips a task through the work-unit encoding and checks the statistics arrive unchanged.Conversion rules (
partition_pruning.rs)file_statisticsnow fills each output column (matched by Iceberg field id) from the task's column statistics, then lets identity partition values replace them where present:noneorcounts) are unknown, never empty. A column that is all nulls may have no bounds; its exact null count alone describes it.record_count.DataFusion's
PrunableStatisticsonly reads exact min/max, so a smallFileStatisticsadapter implementsPruningStatisticsfor one file: it returns min/max whether exact or inexact (pruning only needs bounds) and delegates null and row counts toPrunableStatistics, which still requires them to be exact.Pruner path
Unchanged from #9:
PartitionFilePrunersnapshots the dynamic filters, rewrites a partitioned join's routingCASEas an OR, and builds aPruningPredicate, cached by the filters' generation. Only the statistics it evaluates against changed.Correctness
Same single flag, off by default. Files are checked when the reader takes each task, with the filter's current value; nothing waits for it. Any conversion gap or pruning error keeps the file. The
FilterExecabove the scan still applies the filter, so results are identical with the flag on and off; the tests assert this.Tests
iceberg/tests/dynamic_filter_pruning.rs, single node, unpartitioned taxi table (one day per file), counting data-file reads withCountingStorageFactory, flag off vs on, identical results:CASE), lazy and eager: 9 → 4 files read (2 build + 2 probe instead of 2 + 7). The existing lazy test previously showed 9 → 9.Checks:
cargo fmt --all,cargo clippy -p datafusion-distributed-iceberg -p datafusion-distributed-iceberg-test-tools --all-targets(no new warnings),cargo test -p datafusion-distributed-iceberg,cargo test --features integration --test dynamic_filtering(one known flaky test failed in a parallel run,aggregates::tests::remote_dynamic_filters; all 18 pass with--test-threads=1).