@@ -72,7 +72,7 @@ func (s *searcher) Init(idx *Index, idxCtx *Context, searchSet *SearchSet) {
7272func (s * searcher ) Next (ctx context.Context ) (ok bool , err error ) {
7373 if len (s .levels ) == 0 {
7474 s .levels = ensureSliceLen (s .levels , 1 )
75- root := & s .levels [0 ]
75+ root := & s .levelStorage [0 ]
7676 root .Init (s .idx , s .idxCtx , nil /* parent */ , & s .searchSet .Stats )
7777
7878 // Return enough search results to ensure that:
@@ -105,6 +105,7 @@ func (s *searcher) Next(ctx context.Context) (ok bool, err error) {
105105 // Set up remainder of searchers now that we know the root's level.
106106 n := int (root .Level ()- s .idxCtx .level ) + 1
107107 s .levels = ensureSliceLen (s .levels , n )
108+ s .levels [0 ] = * root
108109 for i := 1 ; i < n ; i ++ {
109110 var maxResults , maxExtraResults int
110111 var matchKey KeyBytes
@@ -238,6 +239,9 @@ func (s *levelSearcher) Init(
238239 searchSet : s .searchSet , // Preserve existing searchSet memory.
239240 }
240241 if parent != nil {
242+ if parent .Level () == InvalidLevel {
243+ panic (errors .AssertionFailedf ("parent level cannot be InvalidLevel" ))
244+ }
241245 s .level = parent .Level () - 1
242246 }
243247
@@ -293,17 +297,28 @@ func (s *levelSearcher) NextBatch(ctx context.Context) (ok bool, err error) {
293297 // overlap with the previous batch, in terms of ordering and duplicates.
294298 s .searchSet .Clear ()
295299
296- if firstBatch || len (s .parentResults ) < s .beamSize {
297- // Get more results from parent to fetch the next batch of child results.
300+ if firstBatch {
301+ ok , err := s .parent .NextBatch (ctx )
302+ if err != nil || ! ok {
303+ return ok , err
304+ }
305+ s .parentResults = s .parent .SearchSet ().PopResults ()
306+ } else if len (s .parentResults ) < s .beamSize {
307+ // Get more results from parent to try and fill the beam size.
298308 parentResults := s .parent .SearchSet ().PopResults ()
299309 if len (parentResults ) == 0 {
300310 // Get next batch of results from parent.
301311 ok , err := s .parent .NextBatch (ctx )
302- if err != nil || ! ok {
303- return ok , err
312+ if err != nil {
313+ return false , err
314+ }
315+ if ! ok && len (s .parentResults ) == 0 {
316+ // Only exit if there are no more results to process.
317+ return false , nil
304318 }
305- s .parentResults = s .parent .SearchSet ().PopResults ()
306- } else if len (s .parentResults ) == 0 {
319+ parentResults = s .parent .SearchSet ().PopResults ()
320+ }
321+ if len (s .parentResults ) == 0 {
307322 s .parentResults = parentResults
308323 } else {
309324 s .parentResults = append (s .parentResults , parentResults ... )
@@ -405,7 +420,10 @@ func (s *levelSearcher) searchChildPartitions(
405420 s .stats .SearchedPartition (level , count )
406421
407422 // If searching for vector to delete, skip partitions that are in a state
408- // that does not allow add and remove operations.
423+ // that does not allow add and remove operations. This is not possible to
424+ // do here for the insert case, because we do not actually search the
425+ // partition in which to insert; we only search its parent and never get
426+ // the metadata for the insert partition itself.
409427 // TODO(andyk): This should probably be checked in the Store, perhaps by
410428 // passing a "forUpdate" parameter to SearchPartitions, so that the Store
411429 // doesn't even add vectors from partitions that do not allow updates.
0 commit comments