Skip to content

promql: add limitk aggregation operator (#88) - #442

Open
petrpan26 wants to merge 3 commits into
opendata-oss:mainfrom
petrpan26:feat/limitk
Open

promql: add limitk aggregation operator (#88)#442
petrpan26 wants to merge 3 commits into
opendata-oss:mainfrom
petrpan26:feat/limitk

Conversation

@petrpan26

@petrpan26 petrpan26 commented May 10, 2026

Copy link
Copy Markdown

Summary

Adds evaluator support for limitk with Prometheus-compatible grouping and filter-shape output.


  • add limitk aggregation reusing the topk/bottomk per-group heap as a push-only buffer
  • walk inputs in fingerprint-sorted order for stable selection
  • extend lowering and physical planning to recognize limitk
  • add limitk-focused operator tests
  • add limitk parity fixtures to aggregators.test

Related Issues

Fixes #88

Test Plan

  • cargo test -p opendata-timeseries --lib
  • cargo clippy -p opendata-timeseries --lib --all-targets -- -D warnings

Checklist

  • Tests added/updated
  • cargo fmt and cargo clippy pass

@petrpan26 petrpan26 changed the title promql: add limitk aggregation operator (#88) [WIP] promql: add limitk aggregation operator (#88) May 10, 2026
@petrpan26

petrpan26 commented May 10, 2026

Copy link
Copy Markdown
Author

Added a draft PR here for review purposes + testing blocking on GreptimeTeam/promql-parser#142 for a new release so we use an official version.

@petrpan26 petrpan26 changed the title [WIP] promql: add limitk aggregation operator (#88) promql: add limitk aggregation operator (#88) May 10, 2026
@petrpan26
petrpan26 force-pushed the feat/limitk branch 2 times, most recently from b9dc872 to 7a19b1a Compare May 10, 2026 06:42
v0.9.0 adds grammar rules for limitk and limit_ratio in the
aggregate_op production. v0.8.0 declared these as `%expect-unused`
tokens but never bound them in the grammar, so `limitk(...)` queries
failed at parse time before this bump.

The bump also widens the token id type from u8 to u16. Updated two
local helper signatures (aggregate_op_name, binary_op_kind) to match.
No behavior change.

@cadonna cadonna left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the PR, @petrpan26 !

I reviewed the production code and had a couple of comments.

I am aware the some comments are not directly related to your code.

Comment thread timeseries/src/promql/operators/aggregate.rs Outdated
Comment thread timeseries/src/promql/operators/aggregate.rs Outdated
continue;
}
// KOrder is unused — limitk never evicts.
heap.push(KHeapEntry {

@cadonna cadonna May 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why do we need to first push the series samples to a heap and then from the heap to out? Why can we not set the samples directly in out?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hi I think I got a very bad case of dumb ai coding in this PR. Upstreams code were reusing the same allocated heap for topk and bottomk and limitk. And i think i blindly follow it. I think our code structure is completely different.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Leave this here so you can actually review the new logic

Comment thread timeseries/src/promql/plan/lowering.rs Outdated
Comment thread timeseries/src/promql/plan/lowering.rs Outdated
Comment thread timeseries/src/promql/plan/lowering.rs Outdated
This PR adds first-class evaluator support for the limitk aggregation. It hooks AggregateOp::Limitk into the aggregation evaluation path with Prometheus-compatible grouping and filter-shape output.

- implement limitk via AggregateKind::Limitk(i64), reusing the topk/bottomk per-group heap as a fixed-capacity push-only buffer (no eviction)
- walk inputs in fingerprint-sorted order so selection is stable per query (Blake3 fingerprint already on SeriesSchema; diverges from upstream's xxhash)
- extend lower_aggregate's shared K-param block to T_TOPK | T_BOTTOMK | T_LIMITK
- extend physical-plan filter-shape to include Limitk
- add limitk-focused operator tests covering by/without grouping, k=0/-1/k>n, mixed validity, multi-step independent selection, fingerprint-sort correctness, and out-of-order tile arrival
- add limitk parity fixtures in aggregators.test (cardinality assertions; full label assertions where output is fully determined)
@petrpan26

Copy link
Copy Markdown
Author

@cadonna Thanks for the review I think I was too enthusiastic when upstream deps was merged and forgot to do an actual code sweep.

@petrpan26
petrpan26 requested a review from cadonna May 12, 2026 13:46
@apurvam

apurvam commented May 13, 2026

Copy link
Copy Markdown
Contributor

Hi @petrpan26 . This looks good. I think the only thing that's missing is to add a memory reservation, like the topk functions do. See should_respect_memory_reservation_for_topk_heap for a test that throws a MemoryLimit error when the topk function exceeds it's memory reservation.

TBH, I'm not exactly sure how this memory limits work, but it's better to be consistent here IMO.

@cadonna

cadonna commented May 13, 2026

Copy link
Copy Markdown
Contributor

Hi @petrpan26 . This looks good. I think the only thing that's missing is to add a memory reservation, like the topk functions do. See should_respect_memory_reservation_for_topk_heap for a test that throws a MemoryLimit error when the topk function exceeds it's memory reservation.

TBH, I'm not exactly sure how this memory limits work, but it's better to be consistent here IMO.

I agree that a test is needed for the memory reservation. However, as limitk does not use a heap, it should only test for the reservation of the grid (line 670 in aggregates.rs). Additionally, as far as I can see test should_respect_memory_reservation_for_topk_heap() does not test what is suggests it tests. The verified error is caused by the grid reservation, not by the heap reservation (line 698 in aggregates.rs). Ideally, we have the following tests:

  • for each of topk, bottomk, limitk, and quantile one test where the reservation of the grid exceeds the cap
  • for each of topk, bottomk one test where the heap exceeds the cap
  • for quantile one test where the sort buffer exceeds the cap

@petrpan26 if you have cycles, you are welcome to fix that in a separate PR.

@cadonna cadonna left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the updates @petrpan26 !

The algorithm looks much better now.

I have one minor comment for the algorithm and two comments for tests.

Comment on lines +1081 to +1082
let grid_base = global_step * in_series_count;
let out_base = global_step * in_series_count;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

grid_base and out_base are always equal, right?
Same question about out_idx and cell.
If yes, you can just use grid_base and cell.

http_requests{group="canary", instance="0", job="app-server"} 700
http_requests{group="production", instance="1", job="app-server"} 600

# Tests for limitk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@cadonna

cadonna commented May 26, 2026

Copy link
Copy Markdown
Contributor

@petrpan26 do you plan to update this PR?
If not, we can merge as is and I can include my feedback on a separate PR.
Just let us know. Either way is fine. We appreciate your contribution.

@petrpan26

Copy link
Copy Markdown
Author

@cadonna im afk this week. Do you mind if i take this on this weekend. If this block anything pls feel free to merge it

@cadonna

cadonna commented May 26, 2026

Copy link
Copy Markdown
Contributor

@petrpan26 It is not blocking anything. I just wanted to understand if the PR is still on your radar. Great that you plan to work on the PR!

@petrpan26

Copy link
Copy Markdown
Author

Looking into this tomorrow !

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.

[tsdb] implement the full set of aggregation operators

3 participants