Skip to content

fix(query-engine): expand self-keyed accumulators in range queries - #587

Draft
milindsrivastava1997 wants to merge 2 commits into
mainfrom
584-range-query-topk-expansion
Draft

fix(query-engine): expand self-keyed accumulators in range queries#587
milindsrivastava1997 wants to merge 2 commits into
mainfrom
584-range-query-topk-expansion

Conversation

@milindsrivastava1997

Copy link
Copy Markdown
Contributor

Summary

  • execute_range_query_pipeline's single-population branch never called get_keys() on the merged value accumulator, so self-keyed accumulators like CountMinSketchWithHeap (top-k) returned empty over a range instead of expanding into their top-k keys — the instant path already does this via collect_results_same_aggregation.
  • Fix: every group now tries merged.get_keys() first (mirroring the instant path exactly) and only falls back to the precomputed key list when it returns None. This also covers self-keyed accumulators stored under a non-None outer key (real Arroyo/worker.rs ingestion always wraps Some(key), even for empty grouping), not just the None-keyed case from the original report.

Fixes #584.

Test plan

  • cargo test -p query_engine_rust --lib native_range_query_tests — 7 passed, including two new regression tests for Range queries drop self-keyed accumulator expansion (top-k) for single-population metrics #584 (range_query_self_keyed_topk_expands_without_keys_query, range_query_self_keyed_topk_expands_with_non_none_outer_key)
  • Full lib suite: cargo test -p query_engine_rust --lib — 554 passed, 0 failed
  • New tests independently verified red (against pre-fix code) / green (against fixed code)

🤖 Generated with Claude Code

…k) without keys_query

execute_range_query_pipeline's single-population branch used each value
group's own store-level group_key directly and never called get_keys() on
the merged value accumulator, so self-keyed accumulators like
CountMinSketchWithHeap (top-k) returned empty over a range instead of
expanding into their top-k keys — the instant path already does this via
collect_results_same_aggregation.

Now every group tries merged.get_keys() first (mirroring the instant path
exactly) and only falls back to the precomputed key list — the store's
group_key for single-population metrics, or the separate keys aggregation's
expansion for dual-population metrics — when get_keys() returns None. This
also covers self-keyed accumulators stored under a non-None outer key (real
Arroyo/worker.rs ingestion always wraps Some(key), even for empty grouping),
not just the None-keyed case from the original report.

Fixes #584.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@milindsrivastava1997

Copy link
Copy Markdown
Contributor Author

execute_range_query_pipeline's merged.get_keys().unwrap_or_else(|| fallback_keys.clone()) (mod.rs:1612) applies unconditionally to every group, including dual-population groups where keys_query.is_some(). That diverges from the instant path (collect_all_results), which branches globally: when a separate keys aggregation exists, collect_results_separate_keys is used and never consults the value accumulator's own get_keys().

This is reachable in production: count_topk_capability_fallback_pairs_heap_with_key_agg (sql.rs:1443) shows capability-matching pairs CountMinSketchWithHeap (value) with DeltaSetAggregator (keys) — a real dual-population, self-keyed-value config. With this change, each window step now uses the heap's own capacity-limited per-window top-k instead of the keys-aggregation's stable, full key set, so a key with low count in a given window can silently drop out of that step (or the set can flap between steps) even though it's present in the instant-query result and every other window.

The new tests (range_query_self_keyed_topk_expands_without_keys_query, ..._with_non_none_outer_key) only cover the single-population case, so this gap isn't caught by CI.

Suggest gating the merged.get_keys() fallback on whether the group came from the single-population branch, so dual-population groups always use the keys-aggregation-derived fallback_keys — matching collect_results_separate_keys.

…eys_query in range queries

Review on #587 caught a regression: the previous fix called
merged.get_keys() unconditionally on every group's merged value
accumulator, including dual-population groups (separate keys_query
present). collect_all_results (instant path) branches globally on query
shape instead — dual-population always goes through
collect_results_separate_keys, which never consults the value
accumulator's own get_keys() at all. A real, tested capability-matched
config (sql.rs) pairs a self-keyed CountMinSketchWithHeap value
aggregation with a separate DeltaSetAggregator keys aggregation; the
previous fix let the heap's own (window-shifting) top-k keys silently
override the keys aggregation's expansion for that config.

Range queries now mirror collect_all_results exactly: dual-population
groups always use the keys aggregation's expansion, full stop; only
single-population groups let the value accumulator's own get_keys() take
priority (falling back to the store-level group key), which is what #584
actually needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.

Range queries drop self-keyed accumulator expansion (top-k) for single-population metrics

1 participant