@@ -8,7 +8,7 @@ use crate::operations::universal_query::collection_query::{
88} ;
99
1010impl Query {
11- fn check_strict_mode (
11+ async fn check_strict_mode (
1212 & self ,
1313 collection : & Collection ,
1414 strict_mode_config : & StrictModeConfig ,
@@ -35,6 +35,54 @@ impl Query {
3535 }
3636 Ok ( ( ) )
3737 }
38+
39+ /// Check that the query does not perform a fullscan based on the collection configuration.
40+ async fn check_fullscan (
41+ & self ,
42+ using : & str ,
43+ collection : & Collection ,
44+ strict_mode_config : & StrictModeConfig ,
45+ ) -> CollectionResult < ( ) > {
46+ // Check only applies on `search_allow_exact`
47+ if strict_mode_config. search_allow_exact == Some ( false ) {
48+ match & self {
49+ Query :: Fusion ( _) | Query :: OrderBy ( _) | Query :: Formula ( _) | Query :: Sample ( _) => ( ) ,
50+ Query :: Vector ( _) => {
51+ let config = collection. collection_config . read ( ) . await ;
52+
53+ // ignore sparse vectors
54+ let query_targets_sparse = config
55+ . params
56+ . sparse_vectors
57+ . as_ref ( )
58+ . is_some_and ( |sparse| sparse. contains_key ( using) ) ;
59+ if query_targets_sparse {
60+ // sparse vectors are always indexed
61+ return Ok ( ( ) ) ;
62+ }
63+
64+ // check HNSW configuration for vector
65+ let vector_hnsw_config = & config
66+ . params
67+ . vectors
68+ . get_params ( using)
69+ . and_then ( |param| param. hnsw_config . as_ref ( ) ) ;
70+
71+ let vector_hnsw_m = vector_hnsw_config. and_then ( |hnsw| hnsw. m ) ;
72+ // TODO(strict-mode) check also payload_m if if there is a filter by tenant/principal
73+ if vector_hnsw_m == Some ( 0 ) {
74+ return Err ( CollectionError :: strict_mode (
75+ format ! (
76+ "Fullscan forbidden on '{using}' – vector indexing is disabled (hnsw_config.m = 0)"
77+ ) ,
78+ "Enable vector indexing or use a prefetch query before rescoring" ,
79+ ) ) ;
80+ }
81+ }
82+ }
83+ }
84+ Ok ( ( ) )
85+ }
3886}
3987
4088impl StrictModeVerification for CollectionQueryRequest {
@@ -45,12 +93,22 @@ impl StrictModeVerification for CollectionQueryRequest {
4593 ) -> CollectionResult < ( ) > {
4694 // CollectionPrefetch.prefetch is of type CollectionPrefetch (recursive type)
4795 for prefetch in & self . prefetch {
48- Box :: pin ( prefetch. check_strict_mode ( collection, strict_mode_config) ) . await ?;
96+ prefetch
97+ . check_strict_mode ( collection, strict_mode_config)
98+ . await ?;
4999 }
50100
51101 if let Some ( query) = self . query . as_ref ( ) {
102+ // check query can perform fullscan when not rescoring
103+ if self . prefetch . is_empty ( ) {
104+ query
105+ . check_fullscan ( & self . using , collection, strict_mode_config)
106+ . await ?;
107+ }
52108 // check for unindexed fields in formula
53- query. check_strict_mode ( collection, strict_mode_config) ?
109+ query
110+ . check_strict_mode ( collection, strict_mode_config)
111+ . await ?
54112 }
55113
56114 Ok ( ( ) )
@@ -89,8 +147,14 @@ impl StrictModeVerification for CollectionPrefetch {
89147 }
90148
91149 if let Some ( query) = self . query . as_ref ( ) {
150+ // check if prefetch can perform a fullscan
151+ query
152+ . check_fullscan ( & self . using , collection, strict_mode_config)
153+ . await ?;
92154 // check for unindexed fields in formula
93- query. check_strict_mode ( collection, strict_mode_config) ?
155+ query
156+ . check_strict_mode ( collection, strict_mode_config)
157+ . await ?
94158 }
95159
96160 Ok ( ( ) )
@@ -124,8 +188,16 @@ impl StrictModeVerification for CollectionQueryGroupsRequest {
124188 strict_mode_config : & StrictModeConfig ,
125189 ) -> CollectionResult < ( ) > {
126190 if let Some ( query) = self . query . as_ref ( ) {
191+ // check query can perform fullscan when not rescoring
192+ if self . prefetch . is_empty ( ) {
193+ query
194+ . check_fullscan ( & self . using , collection, strict_mode_config)
195+ . await ?;
196+ }
127197 // check for unindexed fields in formula
128- query. check_strict_mode ( collection, strict_mode_config) ?
198+ query
199+ . check_strict_mode ( collection, strict_mode_config)
200+ . await ?
129201 }
130202 Ok ( ( ) )
131203 }
0 commit comments