@@ -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 } ;
3333use quickwit_query:: tokenizers:: TokenizerManager ;
3434use quickwit_storage:: {
3535 BundleStorage , ByteRangeCache , MemorySizedCache , OwnedBytes , SplitCache , Storage ,
@@ -45,6 +45,7 @@ use tokio::task::JoinError;
4545use tracing:: * ;
4646
4747use crate :: collector:: { IncrementalCollector , make_collector_for_split, make_merge_collector} ;
48+ use crate :: extract_timestamp_range:: ExtractTimestampRange ;
4849use crate :: metrics:: SEARCH_METRICS ;
4950use crate :: root:: is_metadata_count_request_with_ast;
5051use 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-
913762pub ( crate ) fn rewrite_start_end_time_bounds (
914763 start_timestamp_opt : & mut Option < i64 > ,
915764 end_timestamp_opt : & mut Option < i64 > ,
0 commit comments