Skip to content

[FLINK] Add RowKind column support for Gluten-Flink #12459

Description

@ggjh-159

Description

Background

Follows up on the design note in apache/gluten#12164 (Gluten Flink Pending tasks), where retraction semantics is called out as a pending gap:

retraction semantics — this feature is required for group aggregate and join, which has not been implemented, maybe we should introduce the rowkind just as defined in flink, combine it with row vector.

Flink RowData carries a RowKind enum (+I / -U / +U / -D) that distinguishes changelog records — insert / update-before / update-after / delete. Gluten-Flink hands RowData to the velox C++ engine via the RowData → RowVector conversion path, but RowKind is dropped during that conversion today. As a result, the velox side sees every row as +I regardless of the original changelog marker.

Problem

  • Sink operators (PrintSinkFactory, FileSystemSinkFactory, etc.) can't emit correct -U / +U / -D prefixes for upsert / delete streams — outputs are uniformly +I[...].
  • Retract aggregations, temporal joins, and other row-kind-aware operators lose the row-kind signal once data crosses into velox.
  • Nexmark / E2E tests over upsert streams produce incorrect changelog output.

Proposal

Encode RowKind as a synthetic column that flows through the entire plan and is interpreted at three layers: the Java ↔ C++ boundary, the velox stateful operators that must act on changelog semantics, and the sink layer that emits the changelog prefix.

  • Type: TINYINT (Flink's RowKind enum ordinal: 0=INSERT, 1=UPDATE_BEFORE, 2=UPDATE_AFTER, 3=DELETE).
  • Column name: reserved placeholder, invisible to user SQL($row_kind).
  • Position: trailing column appended by the conversion layer.

The Row-kind-aware operators in velox (retract aggregation, temporal/regular join, top-N, deduplication, etc.) must read it to apply insert / update-before / update-after / delete semantics to their state. Stateful operators that ignore the column would either treat -U / -D as +I (incorrect accumulation) or drop them silently — both wrong.

Preserve the RowKind signal end-to-end across the gluten-flink three-layer architecture (Java / JNI / velox C++), and render the correct +I / -U / +U / -D prefix at the sink layer, establishing the data-carrier foundation for subsequent retract semantics

Design principles: do not pollute velox core data structures, do not pollute the Flink planner, zero intrusion on the Java side.

Task

  • Foundation data structure: New ChangelogRowVector data structure (value + rowKind + appendOnly) + C++ UT
  • Boundary data passing:
    • JNI boundary helpers: split merged RowVector into ChangelogRowVector on input; merge back to merged RowVector on output
    • Input boundary: RowData to merged RowVector conversion appends $row_kind column; Output boundary: merged RowVector to RowData conversion restores RowKind from the trailing column
  • Compute framework compatibility: StreamRecord upgrade (carries ChangelogRowVector) + StatefulOperator base class refactor (split/recompose row kind on input/output, with a row-kind-rebuild virtual hook) + all call-site adaptations
  • Operator adaptation:
    • Source/Calc/Sink Operator(Stateless)
    • agg/window/join ... (Stateful)

Gluten version

main branch

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions