@@ -226,22 +226,11 @@ impl EmbeddingIndexer {
226226 schema_id : u32 ,
227227 field_id : u64 ,
228228 model : & str ,
229- ) -> Result < ( u32 , usize ) , String > {
229+ ) -> Result < ( u32 , usize , u16 ) , String > {
230230 let key = ( schema_id, field_id, model. to_string ( ) ) ;
231-
232- // Check cache first
233- if let Some ( ptr_ref) = self . index_cache . as_ref ( ) . get ( & key) {
234- eprintln ! (
235- "[get_index_info] Cache hit for schema={}, field={}, model={}" ,
236- schema_id, field_id, model
237- ) ;
238- return Ok ( ptr_ref. clone ( ) ) ;
239- }
240-
241- // Load from storage
242231 let index_id = embedding_index_id ( schema_id, field_id, model) ;
243232 eprintln ! (
244- "[get_index_info] Cache miss, loading from storage: schema={}, field={}, model={}, index_id={:?}" ,
233+ "[get_index_info] Loading from storage: schema={}, field={}, model={}, index_id={:?}" ,
245234 schema_id, field_id, model, index_id
246235 ) ;
247236
@@ -269,13 +258,13 @@ impl EmbeddingIndexer {
269258 let dimensions = index_cell[ DIMENSIONS ]
270259 . u32 ( )
271260 . ok_or_else ( || "Invalid index metadata: missing dimensions" . to_string ( ) ) ?;
261+ let ef_search_default = index_cell[ HNSW_EF_SEARCH_DEFAULT ]
262+ . u16 ( )
263+ . copied ( )
264+ . unwrap_or ( 128 ) ;
272265
273- let info = ( * emb_schema_id, * dimensions as usize ) ;
266+ self . index_cache . as_ref ( ) . insert ( key . clone ( ) , ( * emb_schema_id, * dimensions as usize ) ) ;
274267
275- // Update cache
276- self . index_cache . as_ref ( ) . insert ( key. clone ( ) , info) ;
277-
278- // Update models index
279268 let models_key = ( schema_id, field_id) ;
280269 let models_list = match self . index_models . as_ref ( ) . get ( & models_key) {
281270 Some ( list) => list. clone ( ) ,
@@ -289,7 +278,6 @@ impl EmbeddingIndexer {
289278 {
290279 new_list
291280 } else {
292- // Another thread inserted it, get that one
293281 self . index_models . as_ref ( ) . get ( & models_key) . unwrap ( ) . clone ( )
294282 }
295283 }
@@ -299,7 +287,7 @@ impl EmbeddingIndexer {
299287 models_list. write ( ) . push ( model_name) ;
300288 }
301289
302- Ok ( info )
290+ Ok ( ( * emb_schema_id , * dimensions as usize , ef_search_default ) )
303291 }
304292}
305293
@@ -339,14 +327,17 @@ impl EmbeddingIndexerCore for EmbeddingIndexer {
339327 schema_id : u32 ,
340328 field_id : u64 ,
341329 model : & EmbeddingModel ,
330+ hnsw_config : Option < neb:: index:: vector:: HnswConfig > ,
342331 ) -> BoxFuture < ' _ , Result < ( ) , IndexError > > {
343332 let model = model. clone ( ) ;
344333 async move {
334+ let hnsw_config = hnsw_config. unwrap_or_default ( ) ;
345335 eprintln ! (
346- "[Embedding] new_index called: schema={}, field={}, model={}" ,
336+ "[Embedding] new_index called: schema={}, field={}, model={}, hnsw={:?} " ,
347337 schema_id,
348338 field_id,
349- model. name( )
339+ model. name( ) ,
340+ hnsw_config
350341 ) ;
351342
352343 let ( provider_name, model_name) = self . parse_model ( & model) ;
@@ -374,17 +365,17 @@ impl EmbeddingIndexerCore for EmbeddingIndexer {
374365 . await
375366 . map_err ( |e| IndexError :: Other ( e) ) ?;
376367
377- // Create HNSW vector index on the embedding schema's vector field
368+ // Create HNSW vector index on the embedding schema's vector field with provided config
378369 let index_name = format ! ( "EMB-{}-{}-{}" , schema_id, field_id, full_model) ;
379370 self . hnsw_coordinator
380- . new_index ( index_name, emb_schema_id, vector_field_id ( ) , neb :: index :: vector :: HnswConfig :: default ( ) )
371+ . new_index ( index_name, emb_schema_id, vector_field_id ( ) , hnsw_config )
381372 . await
382373 . map_err ( IndexError :: RPCError ) ?
383374 . map_err ( IndexError :: Other ) ?;
384375
385- // Store index metadata
376+ // Store index metadata including HNSW config
386377 let index_cell =
387- new_embedding_index_cell ( schema_id, field_id, & full_model, dims as u32 ) ;
378+ new_embedding_index_cell ( schema_id, field_id, & full_model, dims as u32 , hnsw_config ) ;
388379 self . morph
389380 . neb_client
390381 . write_cell ( index_cell)
@@ -525,10 +516,7 @@ impl EmbeddingIndexerCore for EmbeddingIndexer {
525516 schema_id, field_id, self . default_provider, self . default_model
526517 ) ;
527518
528- // Find the index for this (schema, field)
529- // If multiple models exist, we need to pick one
530- // For now, use the first one found or default
531- let ( model, emb_schema_id) = {
519+ let ( model, emb_schema_id, ef_search_default) = {
532520 let models_key = ( schema_id, field_id) ;
533521 let model_name =
534522 if let Some ( models_list) = self . index_models . as_ref ( ) . get ( & models_key) {
@@ -542,35 +530,25 @@ impl EmbeddingIndexerCore for EmbeddingIndexer {
542530
543531 match model_name {
544532 Some ( model) => {
545- let key = ( schema_id, field_id, model. clone ( ) ) ;
546- if let Some ( ptr_ref) = self . index_cache . as_ref ( ) . get ( & key) {
547- ( model, ptr_ref. clone ( ) . 0 )
548- } else {
549- // Model in index_models but not in cache - lazy load from storage
550- match self . get_index_info ( schema_id, field_id, & model) . await {
551- Ok ( ( emb_schema_id, _) ) => ( model, emb_schema_id) ,
552- Err ( _) => {
553- return Err ( IndexError :: Other ( format ! (
554- "No embedding index found for schema {} field {} (model: {})" ,
555- schema_id, field_id, model
556- ) ) ) ;
557- }
533+ match self . get_index_info ( schema_id, field_id, & model) . await {
534+ Ok ( ( emb_schema_id, _, ef_search_default) ) => ( model, emb_schema_id, ef_search_default) ,
535+ Err ( _) => {
536+ return Err ( IndexError :: Other ( format ! (
537+ "No embedding index found for schema {} field {} (model: {})" ,
538+ schema_id, field_id, model
539+ ) ) ) ;
558540 }
559541 }
560542 }
561543 None => {
562- // Cache miss - try to lazy-load from storage
563- // Try multiple common model variations to handle recovery when
564- // the server was started with different embedding config than during import
565544 let ( provider_name, model_name) = ( self . default_provider . clone ( ) , self . default_model . clone ( ) ) ;
566545 let default_full = Self :: full_model_name ( & provider_name, & model_name) ;
567546
568- // Common model variations to try (order matters - try default first)
569547 let model_variations = vec ! [
570- default_full. clone( ) , // Current default (e.g., "gguf:nomic-embed-text-v1.5")
571- "ollama:nomic-embed-text" . to_string( ) , // Ollama variant
572- "gguf:multilingual-e5-base" . to_string( ) , // Old default GGUF
573- "e5:multilingual-e5-base" . to_string( ) , // E5 variant
548+ default_full. clone( ) ,
549+ "ollama:nomic-embed-text" . to_string( ) ,
550+ "gguf:multilingual-e5-base" . to_string( ) ,
551+ "e5:multilingual-e5-base" . to_string( ) ,
574552 ] ;
575553
576554 eprintln ! ( "[Embedding search] Trying model variations: {:?}" , model_variations) ;
@@ -579,9 +557,9 @@ impl EmbeddingIndexerCore for EmbeddingIndexer {
579557 for model_to_try in & model_variations {
580558 eprintln ! ( "[Embedding search] Attempting: {}" , model_to_try) ;
581559 match self . get_index_info ( schema_id, field_id, model_to_try) . await {
582- Ok ( ( emb_schema_id, _) ) => {
560+ Ok ( ( emb_schema_id, _, ef_search_default ) ) => {
583561 eprintln ! ( "[Embedding search] SUCCESS with model: {}" , model_to_try) ;
584- found_model = Some ( ( model_to_try. clone ( ) , emb_schema_id) ) ;
562+ found_model = Some ( ( model_to_try. clone ( ) , emb_schema_id, ef_search_default ) ) ;
585563 break ;
586564 }
587565 Err ( e) => {
@@ -591,9 +569,8 @@ impl EmbeddingIndexerCore for EmbeddingIndexer {
591569 }
592570 }
593571
594- // Return result or error
595572 match found_model {
596- Some ( ( model, emb_schema_id) ) => ( model, emb_schema_id) ,
573+ Some ( ( model, emb_schema_id, ef_search_default ) ) => ( model, emb_schema_id, ef_search_default ) ,
597574 None => {
598575 return Err ( IndexError :: Other ( format ! (
599576 "No embedding index found for schema {} field {} (tried: {:?})" ,
@@ -625,11 +602,9 @@ impl EmbeddingIndexerCore for EmbeddingIndexer {
625602 . await
626603 . map_err ( |e| IndexError :: Other ( e) ) ?;
627604
628- // Search HNSW (on the embedding schema's vector field)
629605 let query_vector = OwnedPrimArray :: F32 ( result. vector ) ;
630606 let ef_min = 32usize ;
631- let ef_max = 200usize ;
632- let ef_scaled = ( limit * 4 ) . clamp ( ef_min, ef_max) ;
607+ let ef_scaled = ( limit * 4 ) . clamp ( ef_min, ef_search_default as usize ) ;
633608 let ef = std:: cmp:: max ( limit, ef_scaled) as u64 ;
634609
635610 let hits = self
0 commit comments