@@ -45,12 +45,86 @@ impl<'a> QueryAstVisitor<'a> for RangeQueryFields {
4545 }
4646}
4747
48- struct ExistsQueryFastFields {
49- fields : HashSet < FastFieldWarmupInfo > ,
48+ /// Term Queries on fields which are fast but not indexed.
49+ struct TermSearchOnColumnar < ' f > {
50+ fields : & ' f mut HashSet < FastFieldWarmupInfo > ,
5051 schema : Schema ,
5152}
53+ impl < ' a , ' f > QueryAstVisitor < ' a > for TermSearchOnColumnar < ' f > {
54+ type Err = Infallible ;
55+
56+ fn visit_term_set ( & mut self , term_set_query : & ' a TermSetQuery ) -> Result < ( ) , Infallible > {
57+ for field in term_set_query. terms_per_field . keys ( ) {
58+ if let Some ( ( _field, field_entry, path) ) =
59+ find_field_or_hit_dynamic ( field, & self . schema )
60+ {
61+ if field_entry. is_fast ( ) && !field_entry. is_indexed ( ) {
62+ self . fields . insert ( FastFieldWarmupInfo {
63+ name : if path. is_empty ( ) {
64+ field_entry. name ( ) . to_string ( )
65+ } else {
66+ format ! ( "{}.{}" , field_entry. name( ) , path)
67+ } ,
68+ with_subfields : false ,
69+ } ) ;
70+ }
71+ }
72+ }
73+ Ok ( ( ) )
74+ }
75+
76+ fn visit_term (
77+ & mut self ,
78+ term_query : & ' a quickwit_query:: query_ast:: TermQuery ,
79+ ) -> Result < ( ) , Infallible > {
80+ if let Some ( ( _field, field_entry, path) ) =
81+ find_field_or_hit_dynamic ( & term_query. field , & self . schema )
82+ {
83+ if field_entry. is_fast ( ) && !field_entry. is_indexed ( ) {
84+ self . fields . insert ( FastFieldWarmupInfo {
85+ name : if path. is_empty ( ) {
86+ field_entry. name ( ) . to_string ( )
87+ } else {
88+ format ! ( "{}.{}" , field_entry. name( ) , path)
89+ } ,
90+ with_subfields : false ,
91+ } ) ;
92+ }
93+ }
94+ Ok ( ( ) )
95+ }
96+ /// We also need to visit full text queries because they can be converted to term queries
97+ /// on fast fields. We only care about the field being fast and not indexed AND the tokenizer
98+ /// being `raw` or None.
99+ fn visit_full_text ( & mut self , full_text_query : & ' a FullTextQuery ) -> Result < ( ) , Infallible > {
100+ if let Some ( ( _field, field_entry, path) ) =
101+ find_field_or_hit_dynamic ( & full_text_query. field , & self . schema )
102+ {
103+ if field_entry. is_fast ( )
104+ && !field_entry. is_indexed ( )
105+ && ( full_text_query. params . tokenizer . is_none ( )
106+ || full_text_query. params . tokenizer . as_deref ( ) == Some ( "raw" ) )
107+ {
108+ self . fields . insert ( FastFieldWarmupInfo {
109+ name : if path. is_empty ( ) {
110+ field_entry. name ( ) . to_string ( )
111+ } else {
112+ format ! ( "{}.{}" , field_entry. name( ) , path)
113+ } ,
114+ with_subfields : false ,
115+ } ) ;
116+ }
117+ }
118+ Ok ( ( ) )
119+ }
120+ }
52121
53- impl < ' a > QueryAstVisitor < ' a > for ExistsQueryFastFields {
122+ struct ExistsQueryFastFields < ' f > {
123+ fields : & ' f mut HashSet < FastFieldWarmupInfo > ,
124+ schema : Schema ,
125+ }
126+
127+ impl < ' a , ' f > QueryAstVisitor < ' a > for ExistsQueryFastFields < ' f > {
54128 type Err = Infallible ;
55129
56130 fn visit_exists ( & mut self , exists_query : & ' a FieldPresenceQuery ) -> Result < ( ) , Infallible > {
@@ -88,18 +162,11 @@ pub(crate) fn build_query(
88162 search_fields : & [ String ] ,
89163 with_validation : bool ,
90164) -> Result < ( Box < dyn Query > , WarmupInfo ) , QueryParserError > {
91- let mut range_query_fields = RangeQueryFields :: default ( ) ;
92- // This cannot fail. The error type is Infallible.
93- let _: Result < ( ) , Infallible > = range_query_fields. visit ( query_ast) ;
165+ let mut fast_fields: HashSet < FastFieldWarmupInfo > = HashSet :: new ( ) ;
94166
95- let mut exists_query_fields = ExistsQueryFastFields {
96- fields : HashSet :: new ( ) ,
97- schema : schema. clone ( ) ,
98- } ;
167+ let mut range_query_fields = RangeQueryFields :: default ( ) ;
99168 // This cannot fail. The error type is Infallible.
100- let _: Result < ( ) , Infallible > = exists_query_fields. visit ( query_ast) ;
101-
102- let mut fast_fields = HashSet :: new ( ) ;
169+ let Ok ( _) = range_query_fields. visit ( query_ast) ;
103170 let range_query_fast_fields =
104171 range_query_fields
105172 . range_query_field_names
@@ -109,7 +176,18 @@ pub(crate) fn build_query(
109176 with_subfields : false ,
110177 } ) ;
111178 fast_fields. extend ( range_query_fast_fields) ;
112- fast_fields. extend ( exists_query_fields. fields ) ;
179+
180+ let Ok ( _) = TermSearchOnColumnar {
181+ fields : & mut fast_fields,
182+ schema : schema. clone ( ) ,
183+ }
184+ . visit ( query_ast) ;
185+
186+ let Ok ( _) = ExistsQueryFastFields {
187+ fields : & mut fast_fields,
188+ schema : schema. clone ( ) ,
189+ }
190+ . visit ( query_ast) ;
113191
114192 let query = query_ast. build_tantivy_query (
115193 & schema,
@@ -125,6 +203,9 @@ pub(crate) fn build_query(
125203 let mut terms_grouped_by_field: HashMap < Field , HashMap < _ , bool > > = Default :: default ( ) ;
126204 query. query_terms ( & mut |term, need_position| {
127205 let field = term. field ( ) ;
206+ if !schema. get_field_entry ( field) . is_indexed ( ) {
207+ return ;
208+ }
128209 * terms_grouped_by_field
129210 . entry ( field)
130211 . or_default ( )
0 commit comments