[Analytics Backend] Timechart route end-to-end closure (1/30 β 30/30)#21747
Conversation
PR Code Analyzer βAI-powered 'Code-Diff-Analyzer' found issues on commit 46e797d.
The table above displays the top 10 most important findings. Pull Requests Author(s): Please update your Pull Request according to the report above. Repository Maintainer(s): You can Thanks. |
PR Reviewer Guide π(Review updated until commit cc0b9ab)Here are some key observations to aid the review process:
|
PR Code Suggestions β¨Latest suggestions up to cc0b9ab Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit c75f6ad
Suggestions up to commit e9b314c
Suggestions up to commit 2817c6e
Suggestions up to commit 2817c6e
|
|
Persistent review updated to latest commit 2817c6e |
2817c6e to
e9b314c
Compare
|
Persistent review updated to latest commit e9b314c |
|
β Gradle check result for e9b314c: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
e9b314c to
c75f6ad
Compare
|
Persistent review updated to latest commit c75f6ad |
|
β Gradle check result for c75f6ad: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
β¦t split
Two coupled changes that together unblock the no-by family of PPL timechart
queries on the analytics-engine route:
1. Register TIMESTAMPDIFF and TIMESTAMPADD as scalar functions
- Add enum constants to ScalarFunction (analytics-framework SPI)
- Add to STANDARD_PROJECT_OPS in DataFusionAnalyticsBackendPlugin
Clears the capability-layer rejection at OpenSearchProjectRule.annotateExpr.
isthmus-side substrait conversion still needs an adapter (separate commit):
the call shape `TIMESTAMPDIFF(string, ts, ts)` is not in the default
extension catalog. Per-function ITs progress past the capability check and
now report "Unable to convert call TIMESTAMPADD(string, i32,
precision_timestamp<0>?)" β confirms the capability layer is unblocked.
2. Skip OpenSearchAggregateSplitRule when groupSet is not a {0..gc-1} prefix
- matches() now returns false when the ORIGINAL groupSet doesn't equal
ImmutableBitSet.range(groupCount)
The split rule was previously erroring out (IllegalArgumentException,
"Type mismatch ... <aggType> -> <groupType>") for the no-by avg() shape
PPL timechart produces, where the Project below the Aggregate keeps the
raw @timestamp at position 0 and materializes SPAN(@timestamp) at a later
position. FINAL re-used the ORIGINAL's groupSet against PARTIAL's output,
dereferencing a position whose type changed from group-key (TIMESTAMP) to
agg-result. Trying to remap FINAL's groupSet+aggCalls to PARTIAL's leading
positions breaks aggregation semantics (COUNT/AVG need function-swap that
AggregateDecompositionResolver only applies at substrait-conversion time).
Skipping the split for non-prefix groupSets sacrifices distributed
parallelism for correctness β same trade-off pattern as the existing
percentile_approx skip. CalciteStatsCommandIT remains at 47/63 (no
regression), and the 4 no-by + agg() timechart tests now produce correct
data rows (currently failing only on the orthogonal datetime output-cast
issue tracked at opensearch-project/sql#5420).
Signed-off-by: Kai Huang <huangkaics@gmail.com>
β¦er_*
Adds a peephole adapter that constant-folds the exact expression shape PPL
timechart's per_second / per_minute / per_hour / per_day aggregations
produce:
TIMESTAMPDIFF(out_unit, t, TIMESTAMPADD(in_unit, n, t))
When both units are fixed-length (MICROSECOND through WEEK) and the inner
TIMESTAMPADD's base is the same RexNode as the outer TIMESTAMPDIFF's start,
the expression evaluates to the constant n * (in_ms / out_ms) regardless of
t. The adapter materializes that BIGINT literal and lets it flow through
Substrait β eliminating both PPL UDF references in one step (neither has a
Substrait extension binding).
OperatorAnnotation wrappers (AnnotatedProjectExpression introduced by
OpenSearchProjectRule) are peeled at each operand before the structural
comparison, so the wrapped inner TIMESTAMPADD remains recognizable instead
of looking like an annotation RexCall whose operator is ANNOTATED_PROJECT_EXPR.
Out of scope (call falls through unchanged):
- Variable-length out_unit / in_unit (MONTH / QUARTER / YEAR) β fold isn't
safe because milliseconds-per-month depends on which month t lands in.
testTimechartPerSecondWithVariableMonthLengths is an example: span=1M
with per_second expects different per-row results for Feb vs Oct.
- Standalone TIMESTAMPADD (not nested inside TIMESTAMPDIFF) β no adapter
registered for TIMESTAMPADD on its own.
- Non-literal unit / n operands β the peephole requires both to be string
/ integer literals.
Pass-rate impact on the subset this adapter targets (CalciteTimechartPerFunctionIT):
- Before: 6 tests blocked at "Unable to convert call TIMESTAMPADD(string, i32, ...)".
- After: 1 test now reaches client-side assertion (sql#5420 schema-string
cast), 4 tests reveal the orthogonal multi-unit SPAN limitation
(opensearch-project#21584's known gap), 1 test correctly stays blocked on
variable-month-length.
CalciteStatsCommandIT remains at 47/63 (no regression).
Signed-off-by: Kai Huang <huangkaics@gmail.com>
Resolves the 13 by-clause failures in CalciteTimechartCommandIT (5/18 β 18/18) caused by DataFusion's row_number() physical op emitting UInt64 while Calcite types ROW_NUMBER OVER as BIGINT (Int64 signed). Two coupled changes mirror the existing schema_coerce::coerce_inferred_schema bridge the parquet-scan path uses, applied at the partition-stream boundary where the analytics-engine reduce stage reads from upstream PARTIAL fragments via NativeBridge.registerPartitionStream. 1. api::register_partition_stream β coerce the producer's physical schema via schema_coerce before registering the StreamingTable and before writing the IPC bytes back to Java. The Substrait consumer plan's `ensure_schema_compatibility` (datafusion-substrait 53) strict-checks each ReadRel's base_schema against the registered table; the coercion makes Int64-declared plans bind against this table. The Java-side typesMatch tripwire then sees the coerced schema and validates incoming batches against it (next change). 2. api::sender_send β coerce incoming RecordBatches to match the sender's (now-coerced) schema via arrow::compute::cast where types differ. Without this, DataFusion's HashJoin / RepartitionExec panics with "primitive array" on as_primitive::<Int64Type>() of a UInt64 column when the producer's actual batch reaches downstream operators. cast() is the existing Arrow kernel β no-op when the schemas already match, single-cast on the mismatched columns otherwise. Same width preserves zero-copy semantics modulo the bit-reinterpret arrow handles internally. 3. DatafusionReduceSink.typesMatch β relax Java's tripwire to treat same-width Int (any signedness) as compatible, mirroring the existing Timestamp(any precision) tolerance. Same rationale: divergence is harmless because the sender_send coercion produces a downstream- compatible batch. Pass-rate impact: - CalciteTimechartCommandIT: 5/18 β 18/18 β (+13) - CalciteTimechartPerFunctionIT: 1/12 β 1/12 (residuals are opensearch-project#21584's multi-unit-SPAN gap + variable-month TIMESTAMPADD) - Combined timechart: 6/30 β 19/30 (63%) Signed-off-by: Kai Huang <huangkaics@gmail.com>
Closes the 9 CalciteTimechartPerFunctionIT failures of the shape:
source=events_traffic | timechart span=2m per_<unit>(packets) [by host]
The pre-existing SpanAdapter handled time spans only when interval==1
(e.g. `span=1m` β `date_trunc('minute', t)`). Multi-unit time spans
(`span=2m`, `span=12h`, `span=5d`, ...) fell through unchanged, surfacing
to isthmus as `Unable to convert call SPAN(precision_timestamp<0>?, i32,
char<1>)`. DataFusion has `date_bin` for arbitrary-interval bucketing,
but Calcite has no built-in `DATE_BIN` operator and adding one to the
SqlOperator table is out of scope here.
Rewrite for fixed-length units (s, m, h, d, w):
SPAN(t, N, '<unit>')
β CAST(from_unixtime(CAST((to_unixtime(t) / B) * B AS DOUBLE)) AS <result>)
where B = N * unit_seconds.
Component choices (each forced by a binding-time substrait constraint
surfaced during iterative IT runs):
1. `UnixTimestampAdapter.LOCAL_TO_UNIXTIME_OP` + `RustUdfDateTimeAdapters
.LOCAL_FROM_UNIXTIME_OP` instead of Calcite stdlib `UNIX_SECONDS` /
`TIMESTAMP_SECONDS`. The latter bind to BigQuery-named substrait
functions that DF's substrait consumer doesn't register; the locally-
declared operators route through the existing `FunctionMappings.s`
entries to DataFusion's native `to_unixtime` / `from_unixtime` UDFs.
2. No `FLOOR` between divide and multiply. Calcite integer Γ· integer
already truncates toward zero (correct for non-negative epoch
seconds, which all timechart-tested data is). FLOOR(i64) doesn't
bind in substrait β DF's `floor` is floating-point only.
3. `CAST(... AS DOUBLE)` before `from_unixtime`. The yaml signature is
`from_unixtime(fp64) -> precision_timestamp<6>`; without the cast,
isthmus reports `Unable to convert call from_unixtime(i64?)`.
Variable-length units (M, q, y) intentionally fall through β bucketing by
calendar month is not a `N * fixed_seconds` operation. Those tests
(testTimechartPerMonthWithSpecifiedSpan, testTimechartPerSecondWith
VariableMonthLengths) need a real DataFusion `date_bin` interval-month
rewrite, tracked separately.
Pass-rate impact:
- CalciteTimechartPerFunctionIT: 1/12 β 10/12 (+9)
- CalciteTimechartCommandIT: 18/18 (no regression)
- Combined timechart: 19/30 β 28/30 (93%)
Signed-off-by: Kai Huang <huangkaics@gmail.com>
β¦rite
Closes the 2 residual CalciteTimechartPerFunctionIT failures of the shape:
source=events_traffic | timechart span=1M per_second(packets)
source=bank | timechart timefield=birthdate span=1month per_day(balance) by gender
The existing peephole folds TIMESTAMPDIFF(out_unit, t, TIMESTAMPADD(in_unit,
n, t)) to a constant when both units are fixed-length. For variable-length
inner units (MONTH/QUARTER/YEAR), folding isn't safe β the
milliseconds-per-bucket value depends on which calendar month the row's
bucket lands in (Feb 2025 = 28 days = 2_419_200 seconds; Oct 2025 = 31 days
= 2_678_400 seconds). The unfolded TIMESTAMPDIFF call previously fell
through and surfaced as "Unable to convert call TIMESTAMPADD(string, i32,
precision_timestamp<0>?)" because PPL's TIMESTAMPADD/TIMESTAMPDIFF UDFs
have no Substrait extension binding.
This commit extends the adapter to rewrite atomically to a runtime form when
in-unit is variable-length and out-unit is fixed-length:
TIMESTAMPDIFF(out_unit, t, TIMESTAMPADD(MONTH|QUARTER|YEAR, n, t))
β (to_unixtime(DATETIME_PLUS(t, INTERVAL n*m MONTH)) - to_unixtime(t))
* out_factor
where m converts QUARTERβ3 / YEARβ12, INTERVAL_YEAR_MONTH is constructed via
SqlIntervalQualifier(MONTH) (same idiom as EarliestLatestAdapter#
makeIntervalAdd, which proves DATETIME_PLUS(t, INTERVAL_MONTH) binds
end-to-end via Substrait's standard add(timestamp, interval_year_month) into
DataFusion's native interval add), and out_factor scales the unix-seconds
difference to the requested out-unit (MICROSECONDβΓ1_000_000, MILLISECONDβ
Γ1000, SECONDβΓ1, MINUTEβΓ·60, HOURβΓ·3600, DAYβΓ·86400, WEEKβΓ·604800).
Out-unit MONTH/QUARTER/YEAR (variable on both sides) is still rejected β
fixed-second math doesn't apply. No timechart per_* shape needs this.
PPL timechart's per_function always emits MILLISECOND out-unit (see
Chart#transformPerFunction: spanMillis = timestampdiff(MILLISECOND, t,
timestampadd(span.unit, span.value, t))). So the MILLISECOND multiplier path
is the only hot case. The other out-unit factors cover consumer-code shapes
that compute coarser durations from a variable-length bucket.
Pass-rate impact:
- CalciteTimechartPerFunctionIT: 10/12 β 12/12 β
(+2)
- CalciteTimechartCommandIT: 18/18 (no regression)
- Combined timechart: 28/30 β 30/30 β
Signed-off-by: Kai Huang <huangkaics@gmail.com>
c75f6ad to
cc0b9ab
Compare
|
Persistent review updated to latest commit cc0b9ab |
Codecov Reportβ
All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #21747 +/- ##
============================================
- Coverage 73.48% 73.44% -0.04%
+ Complexity 75078 75068 -10
============================================
Files 6012 6016 +4
Lines 340940 341072 +132
Branches 49076 49091 +15
============================================
- Hits 250543 250505 -38
- Misses 70409 70559 +150
- Partials 19988 20008 +20 β View full report in Codecov by Sentry. π New features to boost your workflow:
|
sandeshkr419
left a comment
There was a problem hiding this comment.
Thanks for making the changes.
β¦a date_bin Adds a third lowering path to `SpanAdapter` so dashboard logs-tab histogram queries with sub-second bucket widths (e.g. `span(@timestamp, 40ms)`, `span(@timestamp, 250us)`) work on the analytics-engine route. ## Problem PR opensearch-project#21747 (Timechart route end-to-end closure) added multi-unit time SPAN support for fixed-second units `s`, `m`, `h`, `d`, `w` via integer-seconds arithmetic, intentionally leaving sub-second units out of scope ( `to_unixtime` returns BIGINT seconds and would truncate sub-second precision). The dashboard logs-tab histogram issues queries like `stats count() by span(@timestamp, 40ms)`, which falls outside both the existing `N == 1` `date_trunc` path and the new fixed-second arithmetic path β surfacing as: ``` Unable to convert call SPAN(precision_timestamp<0>?, i32, char<1>) ``` ## Fix Adds a third lowering path checked after the existing two: - `interval == 1`, any unit β `date_trunc(<unit>, field)` (unchanged) - fixed-second + `interval > 1` β integer-seconds arithmetic (opensearch-project#21747, unchanged) - **sub-second + `interval > 1` β `date_bin("<N> <unit>", field)` (new)** DataFusion's `date_bin(stride, source)` accepts a string-form interval stride like `"40 milliseconds"` or `"250 microseconds"` natively. Emitting the stride as a plain string literal avoids substrait interval-type plumbing that would otherwise be needed for sub-second precision, and matches how DataFusion's native parser accepts strides at the SQL surface. Wiring: - `opensearch_scalar_functions.yaml` β new `date_bin` entry, `(stride: string, source: precision_timestamp<P>) β precision_timestamp<P>`. - `SpanAdapter.java` β `SUB_SECOND_UNIT_TO_DATE_BIN_STRIDE` map plus a `LOCAL_DATE_BIN_OP` Calcite SqlFunction, used by the new branch in `adapt()`. - `DataFusionFragmentConvertor.java` β `FunctionMappings.s(SpanAdapter.LOCAL_DATE_BIN_OP, "date_bin")`. Multi-unit month/quarter/year continue to fall through unchanged (variable bucket length needs `date_bin` with an interval-month stride; tracked separately). ## Test plan ### Unit (`SpanAdapterSubSecondTests`, 5/5 pass) - `testMillisecondMultiUnitRewritesToDateBin` β `40ms` lowers to `date_bin("40 milliseconds", field)`. - `testMicrosecondMultiUnitRewritesToDateBin` β `250us` lowers to `date_bin("250 microseconds", field)`. - `testSubSecondUnitOneStaysOnDateTruncPath` β `N == 1` for `us`/`ms` keeps using the cheaper `date_trunc` path (regression guard). - `testFractionalIntervalForSubSecondFallsThrough` β non-integer intervals are not rewritten (would be a planner-level bug; falls through to surface as a normal substrait binding error rather than silent miscalculation). - `testAdaptedDateBinCallPreservesOriginalReturnType` β Project rowType invariant. Full `analytics-backend-datafusion:test` suite passes (no regression of the timechart fixed-second arithmetic path). ### End-to-end (`:run` + `_plugins/_ppl` against a parquet-backed index) | Query | Result | |---|---| | `span(@timestamp, 1h)` | bucket = `00:00:00` (date_trunc path) | | `span(@timestamp, 2h)` | bucket = `00:00:00` (opensearch-project#21747 arithmetic path) | | `span(@timestamp, 40ms)` | **5 distinct 40ms buckets** (`00:07:56.080`, `00:07:56.480`, `00:07:57.200`, `00:07:58`, `00:08:00`) β new path | | Exact dashboard query (filtered range + `stats count() by span(@timestamp, 40ms)`) | 4 buckets within filter range, no errors | Signed-off-by: Kai Huang <ahkcs@amazon.com>
β¦oute Sister to SpanCommandIT (which explicitly scopes to numeric span and the Rust kernel). This new IT exercises all three time-mode lowering paths in SpanAdapter: - N==1 / date_trunc β `span(@timestamp, 1h)`, `span(@timestamp, 1ms)` - N>1 fixed-second arithmetic β `span(@timestamp, 2h)` (opensearch-project#21747) - N>1 sub-second date_bin β `span(@timestamp, 40ms)`, `span(@timestamp, 250us)` (this PR) Adds a focused 5-row `span_time` dataset with explicit sub-second timestamps. The existing `calcs` dataset's `datetime0` field is whole- second only and can't exercise sub-second bucketing. Pairs with the SpanAdapterSubSecondTests JUnit suite β the unit tests assert the rewritten RexCall shape; this IT verifies the end-to-end analytics-engine path (PPL β CalciteRelNodeVisitor β SpanAdapter β Substrait β DataFusion) returns the right buckets. All 5 tests pass on a self-contained QA cluster: - testSpanUnitOneHourLowersToDateTrunc β 5 rows in one 1h bucket - testSpanMultiUnitHoursLowersToArithmetic β 5 rows in one 2h bucket - testSpanFortyMillisecondsBucketsEachRowDistinctly β 5 distinct 40ms buckets - testSpanMicrosecondsBucketsEachRowDistinctly β 5 distinct 250us buckets - testSpanOneMillisecondStaysOnDateTruncPath β regression guard (N=1 ms) Signed-off-by: Kai Huang <ahkcs@amazon.com>
Summary
End-to-end coverage closure for PPL
timecharton the analytics-engine route. Five coupled commits inanalytics-backend-datafusiontakeCalciteTimechart{Command,PerFunction}ITfrom 1/30 β 30/30 β onupstream/main. Each commit corresponds to a distinct Substrait-binding gap surfaced by progressive IT runs against a:runcluster with-Dtests.analytics.force_routing=true -Dtests.analytics.parquet_indices=true.Commits
1.
[Analytics] Wire TIMESTAMPDIFF/TIMESTAMPADD + skip non-prefix-groupSet splitTwo coupled changes:
TIMESTAMPDIFFandTIMESTAMPADDas scalar functions (enum constants inScalarFunction, added toSTANDARD_PROJECT_OPS). Clears the capability-layer rejection atOpenSearchProjectRule.annotateExpr; isthmus-side substrait conversion is still gated by per-call adapters (commit 2).OpenSearchAggregateSplitRule.onMatch()skips the PARTIAL/FINAL alternative when it would emit a row type that fails Volcano'stypeMatchesInferred. Two unsafe shapes today:percentile_approx(2-arg aggregate whose FINAL phase needs(tdigest_state, percent_literal))SqlTypeFamilydiffers from the ORIGINAL input column's family (e.g. PPL timechart's no-byform:groupSet={2}on a[@timestamp:TIMESTAMP, cpu_usage:DOUBLE, SPAN(@timestamp):TIMESTAMP]input where the SUM aggregate's DOUBLE return at position 2 clashes with TIMESTAMP at the same input position).Same-family non-prefix cases (e.g.
group={1}over two INTEGER columns + a NUMERIC agg) still pass through the split unchanged βPlanShapeTests.testJoinWithDifferentGroupKeys_multiShardverifies this. The skip lives inonMatch(notmatches) so the SINGLE+SINGLETON alternative is still registered, giving the planner a coordinator-gather path for the skipped shapes.2.
[Analytics Backend] Add TimestampDiffAdapter peephole for timechart per_*Peephole that constant-folds
TIMESTAMPDIFF(out_unit, t, TIMESTAMPADD(in_unit, n, t))to a BIGINT literal when both units are fixed-length (MICROSECONDβ¦WEEK). Eliminates both PPL UDF references in one step β neither has a Substrait extension binding, so the unfolded calls would surface asUnable to convert call TIMESTAMPADD(...).OperatorAnnotationwrappers introduced byOpenSearchProjectRuleare peeled at each operand before structural comparison.3.
[Analytics Backend] UInt64 β Int64 bridge at partition-stream boundaryAnalytics-engine reduce-stage fragments crashed with
Substrait error: Field '<name>' in Substrait schema has a different type (Int64) than the corresponding field in the table schema (UInt64)when the upstream PARTIAL fragment emitted an Arrow type Substrait/Calcite has no native equivalent for. Canonical case: DataFusion'srow_number()physical op (output: UInt64) feeding a consumer plan that typesROW_NUMBER OVERas BIGINT/Int64.Extends the existing
schema_coerce::coerce_inferred_schemabridge β currently applied only at the parquet-scan boundary β to the partition-stream registration boundary used by every inter-stage exchange:api::register_partition_streamrunscoerce_inferred_schemaon the producer-derived schema beforesession.register_partitionand the IPC return path.api::sender_sendaddscoerce_batch_to_sender_schemaβ casts incomingRecordBatchcolumns to match the sender's coerced schema viaarrow::compute::cast. Without this, DataFusion's HashJoin / RepartitionExec strict-downcasts toInt64Typeand panics with"primitive array".DatafusionReduceSink.typesMatchrelaxed to treat same-widthInt(any signedness) as compatible, mirroring the existingTimestampprecision tolerance.4.
[Analytics Backend] SpanAdapter β multi-unit fixed-length time bucketPre-existing
SpanAdapterhandled time spans only wheninterval==1. Multi-unit spans (span=2m,span=12h,span=5d, ...) fell through unchanged. Rewrite for fixed-length units (s, m, h, d, w):Three component choices were each forced by a binding-time substrait constraint:
LOCAL_TO_UNIXTIME_OP/LOCAL_FROM_UNIXTIME_OP(package-local) instead of Calcite stdlibUNIX_SECONDS/TIMESTAMP_SECONDS. The latter bind to BigQuery-named substrait functions DF's consumer has no entries for.FLOORbetween divide and multiply. Integer Γ· integer already truncates (correct for non-negative epoch seconds);FLOOR(i64)doesn't bind in substrait (DF'sflooris floating-point only).CAST(... AS DOUBLE)beforefrom_unixtime. yaml signature is(fp64) β precision_timestamp<6>.Variable-length units (M, q, y) intentionally fall through β bucketing by calendar month isn't
N Γ fixed_seconds. Commit 5 handles those.5.
[Analytics Backend] TimestampDiffAdapter β variable-month runtime rewriteExtends commit 2's peephole to handle variable-length inner units (MONTH/QUARTER/YEAR) when the out-unit is fixed-length. Folding isn't safe (Feb 2025 = 28 days, Oct 2025 = 31 days β value depends on calendar month). Atomic runtime rewrite:
where
mconverts QUARTERβ3 / YEARβ12,INTERVAL_YEAR_MONTHis built viaSqlIntervalQualifier(MONTH)(same idiom asEarliestLatestAdapter#makeIntervalAdd, which has prior wiring proof thatDATETIME_PLUS(t, INTERVAL_MONTH)binds end-to-end via Substrait's standardadd(timestamp, interval_year_month)into DataFusion's native interval add).PPL's
Chart#transformPerFunctionalways emits MILLISECOND out-unit, so the multiplier path (Γ1000) is the hot case; the divisor path (MINUTEβΓ·60 etc.) covers consumer code shapes that compute coarser durations.Pass-rate impact
Verified locally against
upstream/main+ this PR's full stack:CalciteTimechartCommandITCalciteTimechartPerFunctionITPlanShapeTests.testJoinWithDifferentGroupKeys_multiShard(the multi-shard join-with-non-prefix-groupSet plan-shape regression test) and the 12 otherPlanShapeTestscases also pass β no regression to the existing split rule's coverage.Sandbox check status
./gradlew check -p sandbox -Dsandbox.enabled=trueresults on this branch:-Werrorcompile, spotless, checkstyle, forbiddenApis, licenseHeaders, dependencyLicenses, thirdPartyAudit all clean).:sandbox:qa:analytics-engine-coordinator:internalClusterTestand:sandbox:plugins:composite-engine:internalClusterTest(9 + 2 tests) all surface the sameAllocator[ROOT] closed with outstanding child allocatorsteardown leak. Identical failures reproduce on plainupstream/mainwithout any of this PR's commits β confirmed in a separate run. Unrelated to the code paths this PR touches (SpanAdapter,TimestampDiffAdapter,OpenSearchAggregateSplitRule,register_partition_stream,sender_send,typesMatch).Test plan
CalciteTimechartCommandITβ 18/18 on analytics-engine routeCalciteTimechartPerFunctionITβ 12/12 on analytics-engine routePlanShapeTests(analytics-engine) β 13/13, no regression to non-prefix-groupSet handling./gradlew check -p sandbox -Dsandbox.enabled=trueβ unit-test surface clean; pre-existing flakes in unrelatedinternalClusterTestmodules