Skip to content

[SPARK-58199][SQL] Add FileIndex fullyPushedFilter hint for physical plan#57340

Open
szehon-ho wants to merge 1 commit into
apache:masterfrom
szehon-ho:SPARK-fileindex-fully-pushed-filters
Open

[SPARK-58199][SQL] Add FileIndex fullyPushedFilter hint for physical plan#57340
szehon-ho wants to merge 1 commit into
apache:masterfrom
szehon-ho:SPARK-fileindex-fully-pushed-filters

Conversation

@szehon-ho

@szehon-ho szehon-ho commented Jul 17, 2026

Copy link
Copy Markdown
Member

What changes were proposed in this pull request?

This PR adds an optional fullyPushedFilters hint to the FileIndex trait and
teaches FileSourceStrategy to use it when deciding which filters can be removed
from the row-level FilterExec placed above the scan.

  • FileIndex.fullyPushedFilters: Option[Seq[Expression]] defaults to None.
  • In FileSourceStrategy, the set of post-scan (after-scan) filters is now computed as:
    • When the FileIndex returns Some(fullyPushedFilters), those filters are the
      only basis for removing predicates from the FilterExec above the scan
      (filterSet -- fullyPushedFilters).
    • When it returns None, planning keeps the existing default behavior
      (filterSet -- partitionKeyFilters.filter(_.references.nonEmpty)).

This lets a FileIndex implementation that guarantees certain predicates for all
returned rows (e.g. an index that fully prunes on non-partition columns) tell the
planner exactly which filters are safe to drop, instead of relying only on the
default partition-key heuristic.

Note: in DSV2 , the scalar subquery partition filters are kept on FIlterExec for correctness, but they are removed in DSV1 world.

Why are the changes needed?

Today FileSourceStrategy assumes only partition-key filters are fully satisfied by
file listing, so any other predicate a FileIndex may fully guarantee must still be
re-evaluated in a FilterExec. Custom FileIndex implementations have no way to
communicate stronger pushdown guarantees to the physical plan. The new hint provides
an opt-in mechanism, with no behavior change for existing indexes (default None).

Does this PR introduce any user-facing change?

No. The new trait method has a default implementation returning None, which
preserves the existing planning behavior for all built-in FileIndex implementations.

How was this patch tested?

Added a unit test in FileSourceStrategySuite
("FileIndex fullyPushedFilters controls final FilterExec removal") that exercises a
test FileIndex returning None, Some(Nil), and Some(<data filter>), and asserts
the resulting FilterExec predicates. Ran:

build/sbt 'sql/testOnly *FileSourceStrategySuite -- -z "fullyPushedFilters"'

All tests passed.

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Opus 4.8)

// for removing filters from the row-level FilterExec above the scan.
val afterScanFilters = fsRelation.location.fullyPushedFilters match {
case Some(fullyPushedFilters) => filterSet -- fullyPushedFilters
case None => filterSet -- partitionKeyFilters.filter(_.references.nonEmpty)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit/nonblocker - I wonder if we can always set partition key filters in index when we see it the first time to avoid the fallback; is that possible?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, let me address with the other concern (that we dont call listFiles yet until physical execution..)

… plan

Add an optional fullyPushedFilters(partitionKeyFilters, dataFilters) method to the
FileIndex trait and use it in FileSourceStrategy to determine which filters can be
removed from the row-level FilterExec above the scan. The default implementation
returns partitionKeyFilters, preserving existing behavior.

Co-authored-by: Isaac
@szehon-ho
szehon-ho force-pushed the SPARK-fileindex-fully-pushed-filters branch from 03e3446 to bec1e80 Compare July 17, 2026 21:42
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.

3 participants