Skip to content

Commit d10c70c

Browse files
committed
Reuse new ExtractTimestampRange in leaf search
Does the same as RemoveTimestampRange, but even does a little more.
1 parent 5fdcbfe commit d10c70c

File tree

2 files changed

+7
-158
lines changed

2 files changed

+7
-158
lines changed

quickwit/quickwit-search/src/extract_timestamp_range.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ pub(crate) fn extract_start_end_timestamp_from_ast(
7676
/// `end_timestamp` is to be interpreted as Exclusive (or Unbounded)
7777
/// In other word, this is a `[start_timestamp..end_timestamp)` interval.
7878
#[derive(Debug, Clone)]
79-
struct ExtractTimestampRange<'a> {
80-
timestamp_field: &'a str,
81-
start_timestamp: Bound<DateTime>,
82-
end_timestamp: Bound<DateTime>,
79+
pub(crate) struct ExtractTimestampRange<'a> {
80+
pub(crate) timestamp_field: &'a str,
81+
pub(crate) start_timestamp: Bound<DateTime>,
82+
pub(crate) end_timestamp: Bound<DateTime>,
8383
}
8484

8585
impl ExtractTimestampRange<'_> {

quickwit/quickwit-search/src/leaf.rs

+3-154
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use quickwit_proto::search::{
2929
CountHits, LeafSearchRequest, LeafSearchResponse, PartialHit, ResourceStats, SearchRequest,
3030
SortOrder, SortValue, SplitIdAndFooterOffsets, SplitSearchError,
3131
};
32-
use quickwit_query::query_ast::{BoolQuery, QueryAst, QueryAstTransformer, RangeQuery, TermQuery};
32+
use quickwit_query::query_ast::{BoolQuery, QueryAst, QueryAstTransformer, RangeQuery};
3333
use quickwit_query::tokenizers::TokenizerManager;
3434
use quickwit_storage::{
3535
BundleStorage, ByteRangeCache, MemorySizedCache, OwnedBytes, SplitCache, Storage,
@@ -45,6 +45,7 @@ use tokio::task::JoinError;
4545
use tracing::*;
4646

4747
use crate::collector::{IncrementalCollector, make_collector_for_split, make_merge_collector};
48+
use crate::extract_timestamp_range::ExtractTimestampRange;
4849
use crate::metrics::SEARCH_METRICS;
4950
use crate::root::is_metadata_count_request_with_ast;
5051
use crate::search_permit_provider::{SearchPermit, compute_initial_memory_allocation};
@@ -639,58 +640,6 @@ pub fn map_bound<T, U>(bound: Bound<T>, f: impl FnOnce(T) -> U) -> Bound<U> {
639640
}
640641
}
641642

642-
// returns the max of left and right, that isn't unbounded. Useful for making
643-
// the intersection of lower bound of ranges
644-
fn max_bound<T: Ord + Copy>(left: Bound<T>, right: Bound<T>) -> Bound<T> {
645-
use Bound::*;
646-
match (left, right) {
647-
(Unbounded, right) => right,
648-
(left, Unbounded) => left,
649-
(Included(left), Included(right)) => Included(left.max(right)),
650-
(Excluded(left), Excluded(right)) => Excluded(left.max(right)),
651-
(excluded_total @ Excluded(excluded), included_total @ Included(included)) => {
652-
if included > excluded {
653-
included_total
654-
} else {
655-
excluded_total
656-
}
657-
}
658-
(included_total @ Included(included), excluded_total @ Excluded(excluded)) => {
659-
if included > excluded {
660-
included_total
661-
} else {
662-
excluded_total
663-
}
664-
}
665-
}
666-
}
667-
668-
// returns the min of left and right, that isn't unbounded. Useful for making
669-
// the intersection of upper bound of ranges
670-
fn min_bound<T: Ord + Copy>(left: Bound<T>, right: Bound<T>) -> Bound<T> {
671-
use Bound::*;
672-
match (left, right) {
673-
(Unbounded, right) => right,
674-
(left, Unbounded) => left,
675-
(Included(left), Included(right)) => Included(left.min(right)),
676-
(Excluded(left), Excluded(right)) => Excluded(left.min(right)),
677-
(excluded_total @ Excluded(excluded), included_total @ Included(included)) => {
678-
if included < excluded {
679-
included_total
680-
} else {
681-
excluded_total
682-
}
683-
}
684-
(included_total @ Included(included), excluded_total @ Excluded(excluded)) => {
685-
if included < excluded {
686-
included_total
687-
} else {
688-
excluded_total
689-
}
690-
}
691-
}
692-
}
693-
694643
/// remove timestamp range that would be present both in QueryAst and SearchRequest
695644
///
696645
/// this can save us from doing double the work in some cases, and help with the partial request
@@ -716,7 +665,7 @@ fn remove_redundant_timestamp_range(
716665
.map(Bound::Excluded)
717666
.unwrap_or(Bound::Unbounded);
718667

719-
let mut visitor = RemoveTimestampRange {
668+
let mut visitor = ExtractTimestampRange {
720669
timestamp_field,
721670
start_timestamp,
722671
end_timestamp,
@@ -810,106 +759,6 @@ fn remove_redundant_timestamp_range(
810759
search_request.end_timestamp = None;
811760
}
812761

813-
/// Remove all `must` and `filter timestamp ranges, and summarize them
814-
#[derive(Debug, Clone)]
815-
struct RemoveTimestampRange<'a> {
816-
timestamp_field: &'a str,
817-
start_timestamp: Bound<DateTime>,
818-
end_timestamp: Bound<DateTime>,
819-
}
820-
821-
impl RemoveTimestampRange<'_> {
822-
fn update_start_timestamp(
823-
&mut self,
824-
lower_bound: &quickwit_query::JsonLiteral,
825-
included: bool,
826-
) {
827-
use quickwit_query::InterpretUserInput;
828-
let Some(lower_bound) = DateTime::interpret_json(lower_bound) else {
829-
// we shouldn't be able to get here, we would have errored much earlier in root search
830-
warn!("unparsable time bound in leaf search: {lower_bound:?}");
831-
return;
832-
};
833-
let bound = if included {
834-
Bound::Included(lower_bound)
835-
} else {
836-
Bound::Excluded(lower_bound)
837-
};
838-
839-
self.start_timestamp = max_bound(self.start_timestamp, bound);
840-
}
841-
842-
fn update_end_timestamp(&mut self, upper_bound: &quickwit_query::JsonLiteral, included: bool) {
843-
use quickwit_query::InterpretUserInput;
844-
let Some(upper_bound) = DateTime::interpret_json(upper_bound) else {
845-
// we shouldn't be able to get here, we would have errored much earlier in root search
846-
warn!("unparsable time bound in leaf search: {upper_bound:?}");
847-
return;
848-
};
849-
let bound = if included {
850-
Bound::Included(upper_bound)
851-
} else {
852-
Bound::Excluded(upper_bound)
853-
};
854-
855-
self.end_timestamp = min_bound(self.end_timestamp, bound);
856-
}
857-
}
858-
859-
impl QueryAstTransformer for RemoveTimestampRange<'_> {
860-
type Err = std::convert::Infallible;
861-
862-
fn transform_bool(&mut self, mut bool_query: BoolQuery) -> Result<Option<QueryAst>, Self::Err> {
863-
// we only want to visit sub-queries which are strict (positive) requirements
864-
bool_query.must = bool_query
865-
.must
866-
.into_iter()
867-
.filter_map(|query_ast| self.transform(query_ast).transpose())
868-
.collect::<Result<Vec<_>, _>>()?;
869-
bool_query.filter = bool_query
870-
.filter
871-
.into_iter()
872-
.filter_map(|query_ast| self.transform(query_ast).transpose())
873-
.collect::<Result<Vec<_>, _>>()?;
874-
875-
Ok(Some(QueryAst::Bool(bool_query)))
876-
}
877-
878-
fn transform_range(&mut self, range_query: RangeQuery) -> Result<Option<QueryAst>, Self::Err> {
879-
if range_query.field == self.timestamp_field {
880-
match range_query.lower_bound {
881-
Bound::Included(lower_bound) => {
882-
self.update_start_timestamp(&lower_bound, true);
883-
}
884-
Bound::Excluded(lower_bound) => {
885-
self.update_start_timestamp(&lower_bound, false);
886-
}
887-
Bound::Unbounded => (),
888-
};
889-
890-
match range_query.upper_bound {
891-
Bound::Included(upper_bound) => {
892-
self.update_end_timestamp(&upper_bound, true);
893-
}
894-
Bound::Excluded(upper_bound) => {
895-
self.update_end_timestamp(&upper_bound, false);
896-
}
897-
Bound::Unbounded => (),
898-
};
899-
900-
Ok(Some(QueryAst::MatchAll))
901-
} else {
902-
Ok(Some(range_query.into()))
903-
}
904-
}
905-
906-
fn transform_term(&mut self, term_query: TermQuery) -> Result<Option<QueryAst>, Self::Err> {
907-
// TODO we could remove query bounds, this point query surely is more precise, and it
908-
// doesn't require loading a fastfield
909-
Ok(Some(QueryAst::Term(term_query)))
910-
}
911-
}
912-
913762
pub(crate) fn rewrite_start_end_time_bounds(
914763
start_timestamp_opt: &mut Option<i64>,
915764
end_timestamp_opt: &mut Option<i64>,

0 commit comments

Comments
 (0)