Skip to content

feat: add support for skipping partitions using dynamic filters - #869

Draft
Perseus wants to merge 12 commits into
datafusion-contrib:mainfrom
Perseus:anirudh.singh/iceberg-dyn-filtering-3
Draft

Perseus wants to merge 12 commits into
datafusion-contrib:mainfrom
Perseus:anirudh.singh/iceberg-dyn-filtering-3

Conversation

@Perseus

@Perseus Perseus commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Note

This is part of a stack of PRs that implement dynamic filtering for Iceberg.
The previous PRs can be found here - #850 , #855
Please review this PR starting at dbd4c77
Relevant changes will also be ported to datafusion-iceberg.

Summary

This PR

  • Adds PhysicalExpr -> Iceberg::Predicate translation
  • Uses dynamic filters to skip processing data files based on the partition key(s)

Some of the code in this PR duplicates functionality from iceberg-rust due to those APIs not being public. I will raise PRs/issues in the repo to make them public so that the code can be deleted from here eventually'

Notes

  • Without DF 56, there is a bug in dynamic filters for MIN/MAX that can incorrectly prune files.

@Perseus
Perseus force-pushed the anirudh.singh/iceberg-dyn-filtering-3 branch from 6bfdfaf to 52659af Compare November 9, 2026 21:11
DataFusion offers each scan the filters above it, including the dynamic
filters that joins, top-N sorts and aggregates fill in while the query runs.
Iceberg scans didn't keep them. Keeping them is the first step toward
skipping files with them.

Both scans now keep every pushed filter, ANDed into one predicate. They
answer that they don't apply them, so DataFusion still checks every row.
EXPLAIN shows the dynamic ones on the scan as dynamic_filters=, and the
codecs carry all of them to workers.

With iceberg.dynamic_filtering_enabled on, scans also report the filters
through apply_expressions. Joins and aggregates fill in a dynamic filter only
when a scan reports it, and the coordinator sends updates to the workers
holding those scans. The setting is off by default, and the plan carries it
to workers. Enable it only once every worker supports it: an older worker can
fail a query whose scan reports a dynamic filter.
…ltering is on

With iceberg.dynamic_filtering_enabled off, scans aren't consumers of the
dynamic filters pushed into them, so those filters stay empty. Plans no
longer print them in that case.
Adds a translator from a DataFusion physical filter to an iceberg
predicate. It handles comparisons with a value, IN lists, IS NULL, LIKE
prefixes, isnan, starts_with, AND, OR, NOT and CASE. It also handles the
filters hash joins build while the query runs: IN lists, struct(a, b) IN
(...) for joins on several columns, and the CASE a partitioned join builds
with one branch per partition.

The predicate matches every row the filter keeps, and can match more, so
the filter still runs on every row. An AND can drop a side it can't
convert. A NOT is converted only when its inside was converted fully.

Floats and times aren't converted, and neither are LIKE prefixes with
non-ASCII text. iceberg-rust handles these in ways that could skip
matching rows or fail the read.

Nothing calls it yet. Partition skipping will use it next.
@Perseus
Perseus force-pushed the anirudh.singh/iceberg-dyn-filtering-3 branch from 52659af to ef70cff Compare November 10, 2026 10:22

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant