7878import com .mongodb .client .MongoClient ;
7979import com .mongodb .client .MongoClients ;
8080import com .mongodb .client .MongoCollection ;
81+ import com .mongodb .client .MongoCursor ;
8182import com .mongodb .client .model .IndexOptions ;
8283import com .mongodb .client .model .SearchIndexModel ;
8384import com .mongodb .client .model .SearchIndexType ;
@@ -120,28 +121,49 @@ static void beforeAll() throws InterruptedException {
120121 userCollection .createIndex (new Document ("location.coordinates" , "2d" ), new IndexOptions ());
121122 userCollection .createIndex (new Document ("location.coordinates" , "2dsphere" ), new IndexOptions ());
122123
124+ Thread .sleep (250 ); // just wait a little or the index will be broken
125+ }
126+
127+ /**
128+ * Create the vector search index and wait till it is queryable and actually serving data. Since this may slow down
129+ * tests quite a bit, better call it only when needed to run certain tests.
130+ */
131+ private static void initializeVectorIndex () {
132+
133+ String indexName = "embedding.vector_cos" ;
134+
123135 Document searchIndex = new Document ("fields" ,
124136 List .of (new Document ("type" , "vector" ).append ("path" , "embedding" ).append ("numDimensions" , 5 )
125137 .append ("similarity" , "cosine" ), new Document ("type" , "filter" ).append ("path" , "last_name" )));
126138
127- userCollection .createSearchIndexes (List .of (
128- new SearchIndexModel ("embedding.vector_cos" , searchIndex , SearchIndexType .of (new BsonString ("vectorSearch" )))));
139+ MongoCollection <Document > userCollection = client .getDatabase (DB_NAME ).getCollection (COLLECTION_NAME );
140+ userCollection .createSearchIndexes (
141+ List .of (new SearchIndexModel (indexName , searchIndex , SearchIndexType .of (new BsonString ("vectorSearch" )))));
129142
143+ // wait for search index to be queryable
130144 Awaitility .await ().atMost (Duration .ofSeconds (120 )).pollInterval (Duration .ofMillis (200 )).until (() -> {
131145
132146 List <Document > execute = userCollection
133- .aggregate (
134- List .of (Document .parse ("{'$listSearchIndexes': { 'name' : '%s'}}" .formatted ("embedding.vector_cos" ))))
147+ .aggregate (List .of (Document .parse ("{'$listSearchIndexes': { 'name' : '%s'}}" .formatted (indexName ))))
135148 .into (new ArrayList <>());
136149 for (Document doc : execute ) {
137- if (doc .getString ("name" ).equals ("embedding.vector_cos" )) {
150+ if (doc .getString ("name" ).equals (indexName )) {
138151 return doc .getString ("status" ).equals ("READY" );
139152 }
140153 }
141154 return false ;
142155 });
143156
144- Thread .sleep (250 ); // just wait a little or the index will be broken
157+ Document $vectorSearch = new Document ("$vectorSearch" ,
158+ new Document ("index" , indexName ).append ("limit" , 1 ).append ("numCandidates" , 20 ).append ("path" , "embedding" )
159+ .append ("queryVector" , List .of (1.0 , 1.12345 , 2.23456 , 3.34567 , 4.45678 )));
160+
161+ // wait for search index to serve data
162+ Awaitility .await ().atMost (Duration .ofSeconds (120 )).pollInterval (Duration .ofMillis (200 )).until (() -> {
163+ try (MongoCursor <Document > cursor = userCollection .aggregate (List .of ($vectorSearch )).iterator ()) {
164+ return cursor .hasNext ();
165+ }
166+ });
145167 }
146168
147169 @ BeforeEach
@@ -790,9 +812,9 @@ void testNearReturningGeoPage() {
790812 }
791813
792814 @ Test
793- void vectorSearchFromAnnotation () throws InterruptedException {
815+ void vectorSearchFromAnnotation () {
794816
795- Thread . sleep ( 1000 ); // srly - reindex for vector search
817+ initializeVectorIndex ();
796818
797819 Vector vector = Vector .of (1.00000d , 1.12345d , 2.23456d , 3.34567d , 4.45678d );
798820 SearchResults <User > results = fragment .annotatedVectorSearch ("Skywalker" , vector , Score .of (0.99 ), Limit .of (10 ));
@@ -801,9 +823,9 @@ void vectorSearchFromAnnotation() throws InterruptedException {
801823 }
802824
803825 @ Test
804- void vectorSearchWithDerivedQuery () throws InterruptedException {
826+ void vectorSearchWithDerivedQuery () {
805827
806- Thread . sleep ( 1000 ); // srly - reindex for vector search
828+ initializeVectorIndex ();
807829
808830 Vector vector = Vector .of (1.00000d , 1.12345d , 2.23456d , 3.34567d , 4.45678d );
809831 SearchResults <User > results = fragment .searchCosineByLastnameAndEmbeddingNear ("Skywalker" , vector , Score .of (0.98 ),
@@ -813,9 +835,9 @@ void vectorSearchWithDerivedQuery() throws InterruptedException {
813835 }
814836
815837 @ Test
816- void vectorSearchReturningResultsAsList () throws InterruptedException {
838+ void vectorSearchReturningResultsAsList () {
817839
818- Thread . sleep ( 1000 ); // srly - reindex for vector search
840+ initializeVectorIndex ();
819841
820842 Vector vector = Vector .of (1.00000d , 1.12345d , 2.23456d , 3.34567d , 4.45678d );
821843 List <User > results = fragment .searchAsListByLastnameAndEmbeddingNear ("Skywalker" , vector , Limit .of (10 ));
@@ -824,9 +846,9 @@ void vectorSearchReturningResultsAsList() throws InterruptedException {
824846 }
825847
826848 @ Test
827- void vectorSearchWithLimitFromAnnotation () throws InterruptedException {
849+ void vectorSearchWithLimitFromAnnotation () {
828850
829- Thread . sleep ( 1000 ); // srly - reindex for vector search
851+ initializeVectorIndex ();
830852
831853 Vector vector = Vector .of (1.00000d , 1.12345d , 2.23456d , 3.34567d , 4.45678d );
832854 SearchResults <User > results = fragment .searchByLastnameAndEmbeddingWithin ("Skywalker" , vector ,
@@ -836,9 +858,9 @@ void vectorSearchWithLimitFromAnnotation() throws InterruptedException {
836858 }
837859
838860 @ Test
839- void vectorSearchWithSorting () throws InterruptedException {
861+ void vectorSearchWithSorting () {
840862
841- Thread . sleep ( 1000 ); // srly - reindex for vector search
863+ initializeVectorIndex ();
842864
843865 Vector vector = Vector .of (1.00000d , 1.12345d , 2.23456d , 3.34567d , 4.45678d );
844866 SearchResults <User > results = fragment .searchByLastnameAndEmbeddingWithinOrderByFirstname ("Skywalker" , vector ,
@@ -848,9 +870,9 @@ void vectorSearchWithSorting() throws InterruptedException {
848870 }
849871
850872 @ Test
851- void vectorSearchWithLimitFromDerivedQuery () throws InterruptedException {
873+ void vectorSearchWithLimitFromDerivedQuery () {
852874
853- Thread . sleep ( 1000 ); // srly - reindex for vector search
875+ initializeVectorIndex ();
854876
855877 Vector vector = Vector .of (1.00000d , 1.12345d , 2.23456d , 3.34567d , 4.45678d );
856878 SearchResults <User > results = fragment .searchTop1ByLastnameAndEmbeddingWithin ("Skywalker" , vector ,
0 commit comments