Skip to content

Query aware cost function - #6823

Merged
Abdul-Andha merged 5 commits into
mainfrom
abdul.andha/query-cost
Oct 1, 2026
Merged

Abdul-Andha merged 5 commits into
mainfrom
abdul.andha/query-cost

Conversation

@Abdul-Andha

@Abdul-Andha Abdul-Andha commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Description

Large queries take up a lot of resources in the cluster and can slow down basic queries. We want to protect queries from large "poison pills"

  • Add query aware cost function
    • cost to search a split = hit_cost * query_complexity_factor
    • hit_cost = 5 + num_docs / 100_000 (constant overhead to open split etc + linear cost depending on split size)
    • query_complexity_factor = shape_cost + agg_cost
    • shape_cost is determined by walking the query_ast and adding weights of visited leafs
    • agg_cost is determined by aggregation type and nesting
  • The new cost function is used to:
    • Place jobs at root level and report current load at leaf level
    • Priority queue to grant search permits at leaf level
    • Priority queue for scheduling normal tasks on cpu

How was this PR tested?

  • Unit tests

  • Poison query experiment

    • Same 4-hour time range for all queries (window end: 2026-08-19T19:57:39Z)
    • 7 QPS
    • Repeated the experiment five times for each image (before and after), with a 120-second wait between runs, to reduce outliers and “lucky” runs

    Before

    Metric Baseline During Poison Slowdown
    p50 0.397s 0.777s 1.96x
    p90 0.487s 8.925s 18.33x
    p99 1.078s 33.002s 30.61x
    Queries 2036 1699 -
    Queries >= 10s 1 156 +9%
    Queries >= 30s 0 18 +1%

    With Cost Function

    Metric Baseline During Poison Slowdown
    p50 0.420s 0.632s 1.5x
    p90 0.615s 1.589s 2.58x
    p99 1.068s 4.731s 4.43x
    Queries 2031 1703 -
    Queries >= 10s 0 1 +0%
    Queries >= 30s 0 0 +0%

@Abdul-Andha Abdul-Andha changed the title Abdul.andha/query cost Query aware cost function Sep 25, 2026
@Abdul-Andha
Abdul-Andha marked this pull request as ready for review September 28, 2026 14:29
@Abdul-Andha
Abdul-Andha requested a review from a team as a code owner September 28, 2026 14:29
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-30T22:29:58.359630Z f2b5db7 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2813fb45e0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread quickwit/quickwit-search/src/cost.rs
Comment thread quickwit/quickwit-search/src/cost.rs

// Build requests for each index id
let jobs: Vec<SearchJob> = split_metadatas.iter().map(SearchJob::from).collect();
// query_complexity_factor is 1.0 here (no effect) because list_fields doesn't execute the query

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.

this seems to disagree with comments in with_priority.rs

/// Default tasks have zero priority and cost so short metadata operations, such as
/// list-fields processing, run before split searches.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

the job_cost here is used to place the job and is not related to cpu priority in with_priority.rs

should we use this job_cost for cpu priority too? my idea was this job should be quick on cpu so it can be 0 cost.

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.

oh okay, it wasn't clear to me that we had multiple notions of cost. Before i think we has the same cost function for placing and prioritization

Comment thread quickwit/quickwit-janitor/src/actors/delete_task_planner.rs Outdated
Comment thread quickwit/quickwit-search/src/list_terms.rs
Comment thread quickwit/quickwit-search/src/cost.rs
Comment thread quickwit/quickwit-search/src/cost.rs
Comment thread quickwit/quickwit-search/src/cost.rs Outdated
Comment thread quickwit/quickwit-search/src/cost.rs Outdated
Comment thread quickwit/quickwit-search/src/cost.rs
Comment thread quickwit/quickwit-search/src/search_permit_provider.rs Outdated
Comment thread quickwit/quickwit-search/src/cost.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f2b5db780c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread quickwit/quickwit-search/src/cost.rs
Comment on lines +316 to +318
self.remaining_job_cost = self
.remaining_job_cost
.saturating_sub(permit_request.job_cost);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Fail instead of masking remaining-cost underflow

If the remaining-cost invariant is violated—for example after the unchecked sum in from_task_metadata overflows in a release build—this saturating subtraction logs the error but continues with a zero-cost request, incorrectly promoting corrupted work to the front of the permit queue. Use checked arithmetic and treat an underflow as an invariant failure rather than allowing scheduling to proceed with fabricated state.

AGENTS.md reference: AGENTS.md:L19-L22

Useful? React with 👍 / 👎.

Comment on lines +180 to +187
/// Default tasks have zero priority and cost so short metadata operations, such as
/// list-fields processing, run before split searches.
impl Default for Priority {
fn default() -> Self {
Priority::Normal(0)
Priority::Normal {
priority: 0,
job_cost: 0,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid zero-cost priority for unbounded list-fields work

When a broad list-fields request spans many splits, get_and_process_fields_metadata can enqueue up to 500 deserialization/filtering tasks at once through run_cpu_intensive, and every one now receives this zero cost. Since normal queue ordering prefers lower cost, all of those tasks run before every split search with the same request priority and a positive cost, allowing one metadata request to monopolize the shared search CPU pool. Give these per-split metadata tasks a nonzero size-based cost or otherwise bound their precedence rather than making all default work cheapest.

Useful? React with 👍 / 👎.

Comment on lines +52 to +54
let shape_cost = visitor.total.max(1.0);
let aggregation_cost = agg_cost(search_request.aggregation_request.as_deref())?;
Ok(shape_cost + aggregation_cost)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Include the requested hit count in query cost

A request for one hit and a request for the maximum hit window receive the same complexity factor because only the AST and aggregations are considered here. Per-split top-k collection and merging scale with max_hits, and the leaf request further adds start_offset, so a request with max_hits = 10_000 and start_offset = 10_000 can maintain a 20,000-entry candidate set per split while being queued like a one-hit query. Incorporate the effective leaf hit count into the estimate so large result windows cannot bypass the new scheduling protection.

Useful? React with 👍 / 👎.

}
self.remaining_job_cost = self
.remaining_job_cost
.saturating_sub(permit_request.job_cost);

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.

can we have a warn to know when we saturate so this isn't silent

@Abdul-Andha
Abdul-Andha added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit 271024e Oct 1, 2026
12 checks passed
@Abdul-Andha
Abdul-Andha deleted the abdul.andha/query-cost branch October 1, 2026 19:13
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.

2 participants