Skip to content

[query-runtime] Skip leaf execution for empty dynamic filter - #19470

Draft
wirybeaver wants to merge 1 commit into
apache:masterfrom
wirybeaver:pinot-aqe
Draft

wirybeaver wants to merge 1 commit into
apache:masterfrom
wirybeaver:pinot-aqe

Conversation

@wirybeaver

@wirybeaver wirybeaver commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

PR flow is maintained manually as ASCII in the Design section below.

Summary

This PR replaces the unused partition-coalescing policy with a minimal, executable AQE proof of concept in Pinot's multi-stage engine.

For a dynamic-broadcast SEMI JOIN, the existing pipeline breaker materializes the build side before the probe leaf is compiled. When that runtime result is empty, Pinot now skips constructing and executing the probe-side single-stage requests while preserving the normal multi-stage operator chain, mailbox EOS, pipeline-breaker statistics, and leaf/send statistics.

This is deliberately narrower than changing stage parallelism: Pinot's current streaming mailbox graph is eagerly dispatched and binds routing to concrete workers, so resizing a downstream stage after its producer completes is not yet safe.

Design

build-side mailbox exchange (PIPELINE_BREAKER)
                      |
                      v
          materialize build rows + stats
                      |
                 build empty?
                 /          \
              yes            no
               |              |
      skip probe SSE      construct 1-2 SSE
      request creation      leaf requests
               |              |
               +-------+------+
                       |
                       v
             normal LeafOperator path
                       |
                       v
          mailbox EOS + leaf/send/build stats

The skip decision is explicit: normal LeafOperator construction still requires one or two server requests. Empty-input-sensitive operators—global aggregates and grouping sets containing the grand-total () set—remain on the normal SSE path. EXPLAIN also retains normal request construction.

Roadmap: downstream parallelism AQE

Supporting "complete a stage, then resize an undispatched downstream stage" requires all three seams together:

producer stage
      |
      v
materialized logical partitions (consumer-independent identities)
      |
      v
all-worker completion barrier + exact partition bytes
      |
      v
broker AQE rule: coalesce M logical partitions into K ranges
      |
      v
late-bind ranges to K workers and dispatch consumer stage
  1. Add an opt-in materialized HASH exchange with static parallelism.
  2. Add broker-owned staged dispatch and all-worker completion barriers, initially without adaptation.
  3. Late-bind materialized logical partitions to consumer workers.
  4. Add deterministic contiguous partition coalescing (M -> K) using completed byte statistics.
  5. Harden with stage-attempt fencing, cleanup/quotas, observability, rollout gating, and mixed-version behavior.

Join reordering, dynamic stage insertion/removal, running-stage cancellation, and retries are out of scope for the first rule.

Test Plan

  • 37 focused LeafOperator, pipeline-breaker, and server-plan tests passed.
  • 141 QueryRunnerTest cases passed, including empty-build global aggregation and dynamic-broadcast success/failure paths.
  • ./mvnw spotless:apply -pl pinot-query-runtime
  • ./mvnw checkstyle:check -pl pinot-query-runtime
  • ./mvnw license:format -pl pinot-query-runtime
  • ./mvnw license:check -pl pinot-query-runtime
  • ./mvnw test-compile -pl pinot-query-runtime -Dmaven.compiler.showDeprecation=true -Dmaven.compiler.showWarnings=true

A full dependency build was also attempted but is currently blocked by the existing pinot-segment-local ZstandardDecompressor / org.jetbrains.annotations.NotNull compilation issue.

@codecov-commenter

codecov-commenter commented Sep 5, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.88889% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.24%. Comparing base (7a00b23) to head (d36a227).

Files with missing lines Patch % Lines
...che/pinot/query/runtime/operator/LeafOperator.java 81.81% 0 Missing and 2 partials ⚠️
...ry/runtime/plan/server/ServerPlanRequestUtils.java 66.66% 0 Missing and 1 partial ⚠️
.../runtime/plan/server/ServerPlanRequestVisitor.java 94.11% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             master   #19470       +/-   ##
=============================================
+ Coverage     39.94%   68.24%   +28.30%     
- Complexity     1449     1450        +1     
=============================================
  Files          3520     3520               
  Lines        228940   228951       +11     
  Branches      36313    36317        +4     
=============================================
+ Hits          91453   156253    +64800     
+ Misses       129215    60444    -68771     
- Partials       8272    12254     +3982     
Flag Coverage Δ
integration 100.00% <ø> (ø)
integration1 100.00% <ø> (ø)
integration2 0.00% <ø> (ø)
java-25 68.24% <88.88%> (+28.30%) ⬆️
lane-a 100.00% <ø> (ø)
lane-b 0.00% <ø> (ø)
temurin 68.24% <88.88%> (+28.30%) ⬆️
unittests 68.24% <88.88%> (+28.30%) ⬆️
unittests1 58.14% <88.88%> (?)
unittests2 39.94% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@wirybeaver wirybeaver changed the title [query-runtime] Add adaptive partition coalescing policy [query-runtime] Skip leaf execution for empty dynamic filter Sep 5, 2026
Summary:
- Use the completed dynamic-broadcast pipeline breaker as a real adaptive execution seam.
- Skip constructing and executing probe-side leaf requests when the materialized SEMI JOIN build side is empty.
- Preserve the normal LeafOperator, mailbox EOS, pipeline-breaker statistics, and leaf/send statistics path.
- Keep normal execution for empty-input-sensitive aggregates and EXPLAIN, and preserve rolling-upgrade EnrichedJoinNode support.
- Remove the unused partition-coalescing policy that had no production caller.

Test Plan:
- 37 focused LeafOperator, pipeline-breaker, and server-plan tests passed.
- 141 QueryRunnerTest cases passed, including empty-build global aggregates and dynamic-broadcast success/failure paths.
- Spotless, Checkstyle, license format/check, and module test-compile passed for pinot-query-runtime.
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.

2 participants