Skip to content

[flink] Support projection and filter pushdown for $changelog and $binlog virtual tables - #3759

Open
naivedogger wants to merge 7 commits into
apache:mainfrom
naivedogger:feature/virtual-table-pushdown
Open

[flink] Support projection and filter pushdown for $changelog and $binlog virtual tables#3759
naivedogger wants to merge 7 commits into
apache:mainfrom
naivedogger:feature/virtual-table-pushdown

Conversation

@naivedogger

Copy link
Copy Markdown
Contributor

Purpose

Linked issue: close #3722

The $changelog and $binlog virtual tables did not implement any pushdown
abilities, so every query read the full data row and applied all filters in
Flink. This change lets both virtual-table sources implement
SupportsProjectionPushDown and SupportsFilterPushDown, reducing scanned
columns and, where possible, pushing filters down to the Fluss scan.

Brief change log

  • ChangelogFlinkTableSource now implements SupportsProjectionPushDown and
    SupportsFilterPushDown:
    • Projection: translates the virtual projection (metadata columns
      _change_type/_log_offset/_commit_timestamp + data columns) into the
      physical dataProjection scanned from Fluss and a baseRowProjection that
      reorders the base changelog row during deserialization. A metadata-only
      projection normalizes the scan to a full data-row read to avoid a
      zero-column scan.
    • Filter: pushes partition-key filters (partition pruning) and data-column
      filters (statistics-based record-batch skipping, ARROW log format only);
      metadata-column filters are naturally non-pushable. All filters are still
      returned as remaining so Flink applies them as a safety net (FLINK-38635).
  • BinlogFlinkTableSource now implements both abilities:
    • Projection: top-level projection over
      [_change_type, _log_offset, _commit_timestamp, before, after]; the data
      scan stays full because before/after are whole nested ROWs (nested
      pruning is out of scope).
    • Filter: no top-level column is convertible to a Fluss predicate (metadata is
      non-pushable, data/partition columns are nested inside before/after), so
      nothing is pushed and all filters are returned to Flink; implemented for
      interface parity.
  • Deserialization: ChangelogDeserializationSchema / BinlogDeserializationSchema
    and their row converters honor the projection when building the produced row
    and row type (via ProjectedRowData).

Tests

  • Unit tests:
    • ChangelogFlinkTableSourceTest, BinlogFlinkTableSourceTest — projection
      derivation, partition/data-column/metadata filter routing, statistics
      gating, and copy() state preservation.
    • ChangelogRowConverterTest, BinlogRowConverterTest — change-type
      conversion, before/after nesting, update merge, and projection reordering.
  • Integration tests (run across Flink 1.18/1.19/1.20/2.2):
    • ChangelogVirtualTableITCase — projection, metadata-only projection,
      partition-filter and data-column-filter pushdown (asserted via
      explainSql), startup modes.
    • BinlogVirtualTableITCase — top-level projection, nested field access,
      partitioned tables, startup modes.

API and Format

No public API or storage format changes. The affected sources are internal
Flink connector components.

Documentation

No documentation changes.

…irtual tables

Add projection and filter pushdown to the $changelog and $binlog virtual
table sources, with dedicated converter/source unit tests and end-to-end
ITCases.

Fixes two issues found in review:
- Metadata-only changelog projection produced an empty (zero-column) scan
  and yielded no records; normalize the scan projection to null so the full
  data row is scanned and metadata is selected during deserialization.
- Changelog log filter pushdown is now only enabled for the ARROW log
  format, avoiding an UnsupportedOperationException from
  TableScan#createLogScanner on INDEXED/COMPACTED tables.
Introduce an SLF4J logger in PushdownUtils and emit diagnostics when
statistics collection is disabled, and when a configured statistics
column is skipped due to an unsupported type or because it is absent
from the table schema.

Copilot AI left a comment

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.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Adds projection and filter pushdown support for Flink’s $changelog and $binlog virtual-table sources to reduce scanned columns and push eligible predicates into Fluss scans, while updating converters/deserializers and expanding unit/integration coverage.

Changes:

  • Implement SupportsProjectionPushDown / SupportsFilterPushDown for $changelog and $binlog table sources, including record-batch (statistics) and partition pruning pathways where supported.
  • Update changelog/binlog row converters and deserialization schemas to honor projection via ProjectedRowData and produced type derivation.
  • Add/expand unit and integration tests covering projection derivation, filter routing/pushdown behavior, and projection-aware conversion.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
fluss-flink/fluss-flink-common/src/main/java/org/apache/fluss/flink/source/ChangelogFlinkTableSource.java Implements projection + filter pushdown for $changelog, derives dataProjection and baseRowProjection, adds statistics-based batch filter handling.
fluss-flink/fluss-flink-common/src/main/java/org/apache/fluss/flink/source/BinlogFlinkTableSource.java Implements top-level projection pushdown + filter pushdown interface parity for $binlog (no pushable filters).
fluss-flink/fluss-flink-common/src/main/java/org/apache/fluss/flink/utils/ChangelogRowConverter.java Adds base-row projection support via ProjectedRowData and produced type derivation.
fluss-flink/fluss-flink-common/src/main/java/org/apache/fluss/flink/utils/BinlogRowConverter.java Adds top-level projection support via ProjectedRowData and produced type derivation.
fluss-flink/fluss-flink-common/src/main/java/org/apache/fluss/flink/source/deserializer/ChangelogDeserializationSchema.java Propagates base-row projection into converter and produced type.
fluss-flink/fluss-flink-common/src/main/java/org/apache/fluss/flink/source/deserializer/BinlogDeserializationSchema.java Propagates top-level projection into converter and produced type.
fluss-flink/fluss-flink-common/src/main/java/org/apache/fluss/flink/utils/PushdownUtils.java Extracts statistics-column availability + predicate-eligibility logic into reusable utilities.
fluss-flink/fluss-flink-common/src/main/java/org/apache/fluss/flink/source/FlinkTableSource.java Switches to using PushdownUtils for stats gating of record-batch predicates.
fluss-flink/fluss-flink-common/src/test/java/org/apache/fluss/flink/utils/ChangelogRowConverterTest.java Refactors change-type coverage into parameterized test; adds projection tests.
fluss-flink/fluss-flink-common/src/test/java/org/apache/fluss/flink/utils/BinlogRowConverterTest.java Adds projection-focused converter tests (top-level projection, update merge, delete).
fluss-flink/fluss-flink-common/src/test/java/org/apache/fluss/flink/source/ChangelogVirtualTableITCase.java Adds IT coverage for changelog projection + filter pushdown and metadata-only projection runtime path.
fluss-flink/fluss-flink-common/src/test/java/org/apache/fluss/flink/source/BinlogVirtualTableITCase.java Adds IT coverage for binlog top-level projection.
fluss-flink/fluss-flink-common/src/test/java/org/apache/fluss/flink/source/ChangelogFlinkTableSourceTest.java New unit tests for $changelog pushdown behavior and copy() state preservation.
fluss-flink/fluss-flink-common/src/test/java/org/apache/fluss/flink/source/BinlogFlinkTableSourceTest.java New unit tests for $binlog projection pushdown state and filter handling.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Use the precomputed Fluss row type for record-batch predicate
  conversion instead of re-converting the Flink row type per filter.
- Replace the O(n^2) contains/indexOf projection derivation with a
  LinkedHashMap position lookup (first-appearance order preserved).
- Only include predicates that pass the partition-key-only check in
  partitionFilters to avoid pushing down unsafe partition predicates.
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.

[flink] Add projection and filter pushdown for virtual log tables

2 participants