@@ -264,11 +264,8 @@ private SearchResult resume(int initialVisited, int topK, int rerankK, float thr
264264 rerankedResults .setMaxSize (topK );
265265
266266 int numVisited = initialVisited ;
267- // A bound that holds the minimum similarity to the query vector that a candidate vector must
268- // have to be considered -- will be set to the lowest score in the results queue once the queue is full.
269- var minAcceptedSimilarity = Float .NEGATIVE_INFINITY ;
270267 // track scores to predict when we are done with threshold queries
271- var scoreTracker = threshold > 0 ? new ScoreTracker .TwoPhaseTracker (threshold ) : ScoreTracker .NO_OP ;
268+ var scoreTracker = threshold > 0 ? new ScoreTracker .TwoPhaseTracker (threshold ) : new ScoreTracker .TwoPhaseTracker ( 1.0 ) ;
272269 VectorFloat <?> similarities = null ;
273270
274271 // add evicted results from the last call back to the candidates
@@ -283,37 +280,36 @@ private SearchResult resume(int initialVisited, int topK, int rerankK, float thr
283280 while (candidates .size () > 0 ) {
284281 // we're done when we have K results and the best candidate is worse than the worst result so far
285282 float topCandidateScore = candidates .topScore ();
286- if (topCandidateScore < minAcceptedSimilarity ) {
283+ if (approximateResults . size () >= rerankK && topCandidateScore < approximateResults . topScore () ) {
287284 break ;
288285 }
289286 // when querying by threshold, also stop when we are probabilistically unlikely to find more qualifying results
290- if (scoreTracker .shouldStop ()) {
287+ if (threshold > 0 && scoreTracker .shouldStop ()) {
291288 break ;
292289 }
293290
294291 // process the top candidate
295292 int topCandidateNode = candidates .pop ();
296293 if (acceptOrds .get (topCandidateNode ) && topCandidateScore >= threshold ) {
297294 addTopCandidate (topCandidateNode , topCandidateScore , rerankK );
298-
299- // update minAcceptedSimilarity if we've found K results
300- if (approximateResults .size () >= rerankK ) {
301- minAcceptedSimilarity = approximateResults .topScore ();
302- }
303295 }
304296
305297 // if this candidate came from evictedResults, we don't need to evaluate its neighbors again
306298 if (previouslyEvicted .get (topCandidateNode )) {
307299 continue ;
308300 }
309301
302+ // skip edge loading if we've found a local maximum and we have enough results
303+ if (scoreTracker .shouldStop () && candidates .size () >= rerankK - approximateResults .size ()) {
304+ continue ;
305+ }
306+
310307 // score the neighbors of the top candidate and add them to the queue
311308 var scoreFunction = scoreProvider .scoreFunction ();
312309 var useEdgeLoading = scoreFunction .supportsEdgeLoadingSimilarity ();
313310 if (useEdgeLoading ) {
314311 similarities = scoreFunction .edgeLoadingSimilarityTo (topCandidateNode );
315312 }
316-
317313 var it = view .getNeighborsIterator (topCandidateNode );
318314 for (int i = 0 ; i < it .size (); i ++) {
319315 var friendOrd = it .nextInt ();
0 commit comments