Skip to content

Optimize simple time ranged search queries #5759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tontinton
Copy link
Contributor

@tontinton tontinton commented Apr 19, 2025

When the search request contains a time range, we aborted the optimization of converting unneeded split searches into count queries.

Removed the TODO that was in the code for this.

Split the PR into 2: #5758.

@tontinton tontinton changed the title Optimize time ranged search queries Optimize simple time ranged search queries Apr 19, 2025
@tontinton tontinton force-pushed the optimize-timestamp-range-simple-search branch 2 times, most recently from 804be29 to 61c3b74 Compare April 19, 2025 19:51
Copy link
Collaborator

@rdettai rdettai left a comment

Choose a reason for hiding this comment

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

Thanks for your PR. The way the logic is split here between optimize_split_order and optimize makes it very hard to proof read. Currently it's already a bit confusing because the optimize() logic for each variant depends on the sort order which is different for each variant. It would be good if we could avoid tightening the coupling between the two match statements even further by making the sort orders more complex.

Comment on lines 1076 to 1082
let min_required_splits = splits
.iter()
// splits are sorted by whether they are contained in the request time range
.filter(|split| Self::is_contained(split, &request))
.map(|split| split.num_docs)
// computing the partial sum
.scan(0u64, |partial_sum: &mut u64, num_docs_in_split: u64| {
Copy link
Collaborator

@rdettai rdettai Apr 22, 2025

Choose a reason for hiding this comment

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

Can you explain why this works? Say you have 5 splits:

  • 1 is contained in the request
  • 4 are only overlapping the request

In that case min_required_splits would be 1 here, but there might be a biggest_end_timestamp or smallest_start_timestamp in any of the other splits.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My thoughts were that there's a

.take_while(|partial_sum| *partial_sum < num_requested_docs)

so min_required_splits would not get to be 1, but now I see that I should validate that we actually reached this condition, and only if we reached it to set min_required_splits and optimize, otherwise return early.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I pushed a quick fix, I need to test it, but I think it answers the problem.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I didn't know of std::ops::ControlFlow 😄. Nevertheless, this reaches the limit when iterators stop being practical. A for loop is much more readable here.

@tontinton tontinton force-pushed the optimize-timestamp-range-simple-search branch from 61c3b74 to 851c15c Compare April 22, 2025 20:31
@tontinton
Copy link
Contributor Author

Thanks for your PR. The way the logic is split here between optimize_split_order and optimize makes it very hard to proof read. Currently it's already a bit confusing because the optimize() logic for each variant depends on the sort order which is different for each variant. It would be good if we could avoid tightening the coupling between the two match statements even further by making the sort orders more complex.

It is a bit confusing, I'll try to think of a better way to do this when I have some more time.

@tontinton tontinton force-pushed the optimize-timestamp-range-simple-search branch from 851c15c to 103b8d9 Compare April 22, 2025 20:44
When the search request contains a time range, we aborted the
optimization of converting unneeded split searches into count queries.
@tontinton tontinton force-pushed the optimize-timestamp-range-simple-search branch from 103b8d9 to 69e85ff Compare April 22, 2025 20:44
@rdettai
Copy link
Collaborator

rdettai commented Apr 23, 2025

I would try refactoring this into:

fn optimize()
  match self {
    CandSplitDoBetter::SplitIdHigher(_) => optimize_split_id_higher()
    CandSplitDoBetter::SplitTimestampLower(_) => optimize_split_timesamp_lower()
    ...
    CanSplitDoBetter::Uninformative => {}
  }

where optimize_split_xxx:

  • sorts
  • returns early if !is_simple_all_query
  • applies its variant specific optimization

This would regroup the optimizations logics with the sorts they depend on to be correct. (To help the review, ideally, re-implement the current logic in 1 commit, and in a separate commit add you logic extension.)

Thanks!

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