Skip to content

Conversation

@dnhatn
Copy link
Member

@dnhatn dnhatn commented Oct 29, 2025

This change adds a window parameter to AggregateFunction, similar to the existing filter parameter. The window parameter is optional but must never be null. This PR also generalizes AggregateFunction to be composed of [source, field, filter, window, extra parameters] , with all extra parameters placed after filter and window.

The implementation of the window function will be added in a follow-up and will initially be available only for time-series aggregations such as rate, avg_over_time, etc.

@dnhatn dnhatn requested review from kkrik-es and nik9000 October 29, 2025 17:36
@dnhatn dnhatn marked this pull request as ready for review October 29, 2025 17:37
@elasticsearchmachine elasticsearchmachine added Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) Team:StorageEngine labels Oct 29, 2025
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-analytical-engine (Team:Analytics)

@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-storage-engine (Team:StorageEngine)

@dnhatn dnhatn requested a review from bpintea October 29, 2025 17:37
@dnhatn dnhatn requested a review from kkrik-es October 29, 2025 17:40
@dnhatn
Copy link
Member Author

dnhatn commented Oct 30, 2025

I wonder if this suffices for now. Can we postpone adding the window to AggregateFunction, until we generalize window functions outside TS? Or, we need to pass the window param to the outer aggs that wrap time-series aggs?

Thanks Kostas! The issue is that time-series aggregations are translated to regular aggregations (e.g., sum(avg_over_time(f, 5m)) becomes sum(avg(f))), which removes the window information. I considered introducing WindowAggregateFunction to wrap aggregation functions with a window (e.g., sum(avg_over_time(f, 5m)) becomes sum(window(avg(f), 5m))). This approach works but is fragile, as some places check aggregation function types (see

) and it is much more complex than the current approach (we need to update the translation and verification rules). The current approach is similar to what we have with the inline filter. I can revise WindowAggregateFunction if we decide not to modify AggregateFunction. However, currently, the window parameter is only exposed to users for time-series aggregates, not for other aggregate functions.

@dnhatn dnhatn requested a review from kkrik-es October 30, 2025 05:14
@kkrik-es
Copy link
Contributor

Makes sense, thanks for the detailed explanation. Window functions will be generalized down the road, so this is unavoidable either way.

* Whether the aggregate function has a window different than NO_WINDOW.
*/
public boolean hasWindow() {
boolean zero = window instanceof Literal lit && lit.value() instanceof Duration duration && duration.isZero();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be:

if (window instanceof Literal lit && lit.value() instanceof Duration duration) {
  return duration.isZero() == false;
}
return false;

@Override
protected NodeInfo<Rate> info() {
return NodeInfo.create(this, Rate::new, field(), timestamp);
return NodeInfo.create(this, Rate::new, field(), filter(), window(), timestamp);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: we missed filter, how important is this? Shall we backport just this to 9.2?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will open a PR for 9.2.1.

Copy link
Contributor

@kkrik-es kkrik-es left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, good progress!

Copy link
Contributor

@bpintea bpintea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the need to add the window param to AggregateFunction (vs just TimeSeriesAggregateFunction) will be revealed later (possibly streaming command?).

* such as {@link Rate} or {@link MaxOverTime}.
*/
public abstract class TimeSeriesAggregateFunction extends AggregateFunction {
public static final Literal NO_WINDOW = Literal.timeDuration(Source.EMPTY, Duration.ZERO);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a dup of the one in AggregateFunction.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, removed it in 3ec11b9.

super(source, CollectionUtils.combine(asList(field, filter, window), parameters));
this.field = field;
this.filter = filter;
this.window = Objects.requireNonNull(window, "[window] must be specified; use NO_WINDOW instead");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we expect functions to check against negative durations?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we should, but our random tests may pass any expression for this parameter.

@dnhatn
Copy link
Member Author

dnhatn commented Oct 30, 2025

@kkrik-es @bpintea Thank you so much for the quick review!

@dnhatn dnhatn merged commit 97e4ff3 into elastic:main Oct 30, 2025
33 of 34 checks passed
@dnhatn dnhatn deleted the add-window-to-aggregate-function branch October 30, 2025 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:Analytics/ES|QL AKA ESQL >non-issue :StorageEngine/TSDB You know, for Metrics Team:Analytics Meta label for analytical engine team (ESQL/Aggs/Geo) Team:StorageEngine v9.3.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants