test(integ-test): stabilize FIRST/LAST/TAKE across shards - #5719
test(integ-test): stabilize FIRST/LAST/TAKE across shards#5719mengweieric wants to merge 2 commits into
Conversation
PR Reviewer Guide 🔍(Review updated until commit 2c34ab4)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to 81eae66 Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit 73ddcdb
Suggestions up to commit b686a1f
Suggestions up to commit a22f944
Suggestions up to commit fe7d053
Suggestions up to commit fe7d053
|
|
Persistent review updated to latest commit 21cc90f |
|
Persistent review updated to latest commit 6e32d15 |
6e32d15 to
a22f944
Compare
|
Persistent review updated to latest commit a22f944 |
|
Persistent review updated to latest commit 4436897 |
|
Persistent review updated to latest commit fe7d053 |
1 similar comment
|
Persistent review updated to latest commit fe7d053 |
fe7d053 to
a22f944
Compare
|
Persistent review updated to latest commit a22f944 |
| // FIRST always skips null measures, whether it follows document order or an explicit sort. | ||
| if (candidateValue != null) { | ||
| acc.setValue(candidateValue); | ||
| if (OrderedAggregateUtils.hasSortKeys(values)) { |
There was a problem hiding this comment.
Why not regiester FIRST/LAST as window function. A UDAF itself should not know the input is sorted or not.
@dai-chen has comments on previous PR. #4223 (review)
There was a problem hiding this comment.
Calcite’s FIRST_VALUE/LAST_VALUE windows preserve input cardinality and would bypass the existing aggregate pushdown, while PPL stats reduces to one row per group. I’ve instead kept FIRST/LAST unchanged and implemented the ordered variants as dedicated arg-min/arg-max aggregates that do not assume sorted input and still push down as sorted top_hits. Could you take another look?
There was a problem hiding this comment.
My concern is why FIRST/LAST required a UDAF, It should be window function, right?
source=account
| sort age
| stats first(firstname) by gender
The SQL will be
SELECT gender, firstname AS "first(firstname)"
FROM (
SELECT gender, firstname,
ROW_NUMBER() OVER (PARTITION BY gender ORDER BY age NULLS FIRST) AS rn
FROM accounts
WHERE firstname IS NOT NULL
) t
WHERE rn = 1;
There was a problem hiding this comment.
Yes, that is the right call. FIRST and LAST are now implemented as window functions rather than sort-aware aggregates, following the shape you outlined. A preceding sort is lowered into a partitioned ROW_NUMBER, the top-ranked row per group is selected, and null values are excluded before ranking so the first or last non-null value is returned. LAST simply reverses the ordering. The aggregate implementations themselves no longer have any notion of input ordering.
There was a problem hiding this comment.
After deep look, I think the first/last function by definition is non-deterministic.
https://spark.apache.org/docs/latest/api/sql/agg-functions/#first
If it is just IT failed in multiple shard use case, try to use makeresults | stats first(xxx) to get deterministic results.
There was a problem hiding this comment.
Updated following your latest suggestion. The engine changes have been removed. Exact FIRST/LAST stream behavior is now tested with makeresults, while multi-document index tests retain alias, nested, grouped, eval, pushdown, paginating, and no-pushdown coverage using membership assertions that do not assume shard order. A full five-primary-shard integTestRemote run executed 7,714 tests with zero FIRST/LAST/TAKE aggregate failures.
|
Persistent review updated to latest commit b686a1f |
|
Persistent review updated to latest commit 73ddcdb |
|
Persistent review updated to latest commit 81eae66 |
…order first() and last() select by input-stream position, which is not defined across shards. Tests that asserted a specific document are made deterministic in one of two ways. Tests whose intent is stream-position semantics build the stream with makeresults, so the order is defined by the literal rows. Tests whose intent is index-backed field access (text, deep nested, alias, script) stay on the index and narrow to a single candidate document per output cell, keeping the field-access path under test. No production code is changed. Signed-off-by: Eric Wei <menwe@amazon.com>
Keep deterministic makeresults tests for exact stream-position semantics, while restoring multi-document index queries with membership assertions that do not assume shard order. This retains alias, nested, grouped, eval, TAKE, pushdown, and no-pushdown coverage without imposing deterministic FIRST/LAST results across shards. Signed-off-by: Eric Wei <menwe@amazon.com>
81eae66 to
2c34ab4
Compare
|
Persistent review updated to latest commit 2c34ab4 |
Summary
FIRST, LAST, and TAKE depend on input encounter order, which is not stable across shards. This change makes their integration tests deterministic without changing production behavior.
The tests use two complementary strategies:
makeresultsprovides a defined input stream for exact assertions about first versus last, grouped selection, null skipping, mixed aggregates, and TAKE cardinality.No production code is changed.
Coverage
The index-backed tests retain coverage for:
count()andavg()assertionsTAKE assertions verify the requested result size, distinct source documents for the current unique-value fixtures, and source-value membership. Deterministic
latest()andearliest()assertions remain exact.Validation
integTestRemoteagainst an external cluster forced to five primary shards: 7,714 tests executed. All FIRST, LAST, and TAKE aggregate tests passed. Remaining failures were outside the modified test areas.makeresultstests failed as expected, while the multi-document membership tests remained valid. This verifies that the two layers enforce different parts of the contract.mainand reran the affected five-shard suites successfully.:integ-test:spotlessCheck,:integ-test:compileTestJava, andgit diff --checkpass.Related: #5716