Skip to content

[FLINK-39986][table-planner][python] Support Common Sub-expression Elimination (CSE) for Python UDFs#28638

Open
raoraoxiong wants to merge 5 commits into
apache:masterfrom
raoraoxiong:FLINK-39986-python-cse
Open

[FLINK-39986][table-planner][python] Support Common Sub-expression Elimination (CSE) for Python UDFs#28638
raoraoxiong wants to merge 5 commits into
apache:masterfrom
raoraoxiong:FLINK-39986-python-cse

Conversation

@raoraoxiong

Copy link
Copy Markdown
Contributor

What is the purpose of the change

This pull request implements Common Sub-expression Elimination (CSE) for Python UDFs in Flink SQL. When a query contains identical deterministic Python UDF calls (e.g., SELECT udf1(x), udf1(x) or SELECT udf1(x), udf2(udf1(x))), the current implementation sends each call independently to the Python worker, resulting in redundant cross-process (JVM ↔ Python Worker) communication and computation. This PR deduplicates such calls so that each unique expression is computed only once, and duplicate positions reference the pre-computed result.

Brief change log

Phase 1: Top-level projection deduplication (Commit 1)

  • Modify CommonExecPythonCalc to deduplicate identical deterministic Python UDF calls in the projection list at the ExecNode level
  • Append a ref-reuse projection operator to expand deduplicated results back to the expected output schema
  • Add ProjectionCodeGenerator.generateProjectionOperator for the expansion projection

Phase 2: Full-tree CSE and condition-projection deduplication (Commit 2)

  • Add PythonCallDeduplicator and PythonCallCseResult for structural deduplication with nested sub-expression flattening and reference maps
  • Add PythonFunctionInfo.ResultRef for referencing pre-computed UDF results by index
  • Extend protobuf Input message with refIndex field
  • Modify Python worker (operations.py) to support sequential execution with result references
  • Add RemoteCalcConditionProjectionCseRule optimizer rule to deduplicate Python UDF calls shared between WHERE conditions and SELECT projections
  • Register the new rule in stream and batch rule sets

Verifying this change

This change added tests and can be verified as follows:

  • Added CommonExecPythonCalcRefReuseTest (Java unit test) to verify deduplication logic, ref-map resolution, and detail name generation with parameterized test cases
  • Added PythonCalcConditionCseTest (Scala plan test) to verify the optimizer rule produces correct plans for condition-projection CSE scenarios
  • Added test_scalar_function_cse.py (Python unit test) to verify the sequential execution codegen path (with refIndex) and the traditional lambda path (without refIndex)
  • Added integration tests in test_udf.py to verify end-to-end correctness of CSE with real Python UDFs

Does this pull request potentially affect one of the following parts:

  • Dependencies (does it add or upgrade a dependency): no
  • The public API, i.e., is any changed class annotated with @Public(Evolving): no
  • The serializers: no
  • The runtime per-record code paths (performance sensitive): no
  • Anything that affects deployment or recovery: JobManager (and its components), Checkpointing, Kubernetes/Yarn, ZooKeeper: no
  • The S3 file system connector: no

Documentation

  • Does this pull request introduce a new feature? yes
  • If yes, how is the feature documented? JavaDocs

Was generative AI tooling used to co-author this PR?
  • Yes — Claude-4.6-Opus

…uplication for Python UDFs

This commit implements Phase 1 of Python UDF Common Sub-expression
Elimination (CSE). Identical deterministic Python UDF calls in the
projection list are deduplicated at the ExecNode level, reducing
redundant cross-process (JVM <-> Python Worker) communication.

Key changes:
- Modify CommonExecPythonCalc to deduplicate top-level calls and
  append a ref-reuse projection operator to restore output schema
- Add ProjectionCodeGenerator.generateProjectionOperator for the
  expansion projection
- Add unit tests and integration tests

Generated-by: Claude-4.6-Opus
…ion-projection deduplication for Python UDFs

This commit implements Phase 2 of Python UDF CSE. It extends the
deduplication to nested sub-expressions (full-tree CSE) and adds a
new optimizer rule to deduplicate Python UDF calls shared between
WHERE conditions and SELECT projections.

Key changes:
- Add PythonCallDeduplicator and PythonCallCseResult for structural
  deduplication with nested sub-expression reference maps
- Add PythonFunctionInfo.ResultRef for referencing pre-computed results
- Extend protobuf Input message with refIndex field
- Modify Python worker (operations.py) to support sequential execution
  with result references
- Add RemoteCalcConditionProjectionCseRule optimizer rule
- Register the new rule in stream and batch rule sets
- Add plan tests and integration tests

Generated-by: Claude-4.6-Opus
@flinkbot

flinkbot commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands The @flinkbot bot supports the following commands:
  • @flinkbot run azure re-run the last Azure build

@raoraoxiong

Copy link
Copy Markdown
Contributor Author

hi @liuyongvs @snuyanzin ,please take a look.

@snuyanzin

snuyanzin commented Jul 4, 2026

Copy link
Copy Markdown
Contributor
  1. please follow contributors guidelines first, current PR is not ready to be reviewed. As an example: CI is not green
  2. Please do not create new classes in scala
  3. do not use deprecated Calcite api especially for new rules

…moteCalcCallFinder to RemoteCallFinder

Fix typo in RemoteCalcConditionProjectionCseRule constructor parameter
type. The correct interface name is RemoteCallFinder, not
RemoteCalcCallFinder.

Generated-by: Claude-4.6-Opus
…d use RelRule API

- Convert RemoteCalcConditionProjectionCseRule from Scala to Java using
  the modern RelRule<Config> pattern instead of deprecated RelOptRule
- Convert PythonCalcConditionCseTest from Scala to Java
- Update PythonCalcSplitRule to use Config-based rule instantiation

Generated-by: Claude-4.6-Opus
…avoid projection pushdown

Use addTableSource with Schema instead of CREATE TABLE with values
connector to prevent projection pushdown from changing the plan output.

Generated-by: Claude-4.6-Opus
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