@@ -515,6 +515,42 @@ public void testExplainFiltered() throws IOException {
515515 }
516516 }
517517
518+ public void testExplainTieBreak () throws IOException {
519+ try (Directory d = newDirectoryForTest ()) {
520+ // All five docs share one vector, so they all score equally. With top k = 3, two are dropped
521+ // due to tie-break.
522+ try (IndexWriter w = new IndexWriter (d , new IndexWriterConfig ())) {
523+ for (int j = 0 ; j < 5 ; j ++) {
524+ Document doc = new Document ();
525+ doc .add (getKnnVectorField ("field" , new float [] {1 , 1 }));
526+ w .addDocument (doc );
527+ }
528+ w .forceMerge (1 );
529+ }
530+ try (IndexReader reader = DirectoryReader .open (d )) {
531+ IndexSearcher searcher = new IndexSearcher (reader );
532+ AbstractKnnVectorQuery query = getKnnVectorQuery ("field" , new float [] {1 , 1 }, 3 );
533+
534+ Set <Integer > collected = new HashSet <>();
535+ for (ScoreDoc sd : searcher .search (query , 3 ).scoreDocs ) {
536+ collected .add (sd .doc );
537+ }
538+ int dropped = -1 ;
539+ for (int doc = 0 ; doc < 5 ; doc ++) {
540+ if (collected .contains (doc ) == false ) {
541+ dropped = doc ;
542+ break ;
543+ }
544+ }
545+ Explanation nomatch = searcher .explain (query , dropped );
546+ assertFalse (nomatch .isMatch ());
547+ String description = nomatch .getDescription ();
548+ assertTrue (description , description .startsWith ("Not in top 3 doc(s): score " ));
549+ assertTrue (description , description .endsWith (" (tie-break or approximate-search miss)" ));
550+ }
551+ }
552+ }
553+
518554 /** Test that when vectors are abnormally distributed among segments, we still find the top K */
519555 public void testSkewedIndex () throws IOException {
520556 /* We have to choose the numbers carefully here so that some segment has more than the expected
0 commit comments