99import com .microsoft .semantickernel .data .vectorsearch .VectorSearchResult ;
1010import com .microsoft .semantickernel .data .vectorstorage .VectorStoreRecordCollection ;
1111import com .microsoft .semantickernel .data .vectorstorage .definition .DistanceFunction ;
12+ import com .microsoft .semantickernel .data .vectorstorage .definition .IndexKind ;
13+ import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordDataField ;
14+ import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordDefinition ;
15+ import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordField ;
16+ import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordKeyField ;
17+ import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordVectorField ;
1218import com .microsoft .semantickernel .data .vectorstorage .options .VectorSearchOptions ;
1319import oracle .jdbc .OracleConnection ;
1420import oracle .jdbc .datasource .impl .OracleDataSource ;
1521import org .junit .jupiter .api .BeforeAll ;
1622import org .junit .jupiter .api .BeforeEach ;
23+ import org .junit .jupiter .api .Nested ;
1724import org .junit .jupiter .api .Test ;
1825import org .junit .jupiter .params .ParameterizedTest ;
1926import org .junit .jupiter .params .provider .Arguments ;
2027import org .junit .jupiter .params .provider .EnumSource ;
2128import org .junit .jupiter .params .provider .MethodSource ;
29+ import java .sql .Connection ;
30+ import java .sql .PreparedStatement ;
31+ import java .sql .ResultSet ;
2232import java .sql .SQLException ;
33+ import java .sql .Statement ;
2334import java .time .Duration ;
2435import java .util .Arrays ;
2536import java .util .List ;
@@ -42,7 +53,6 @@ public class OracleVectorStoreRecordCollectionTest {
4253 private static final OracleDataSource DATA_SOURCE ;
4354 private static final OracleDataSource SYSDBA_DATA_SOURCE ;
4455
45-
4656 static {
4757
4858 try {
@@ -339,6 +349,155 @@ public void searchWithTagFilter() {
339349 assertEquals (hotels .get (1 ).getId (), results .get (0 ).getRecord ().getId ());
340350 }
341351
352+ @ Nested
353+ class HNSWIndexTests {
354+ @ Test
355+ void testHNSWIndexIsCreatedSuccessfully () throws Exception {
356+ VectorStoreRecordKeyField keyField = VectorStoreRecordKeyField .builder ()
357+ .withName ("id" )
358+ .withStorageName ("id" )
359+ .withFieldType (String .class )
360+ .build ();
361+
362+ VectorStoreRecordDataField dummyField = VectorStoreRecordDataField .builder ()
363+ .withName ("dummy" )
364+ .withStorageName ("dummy" )
365+ .withFieldType (String .class )
366+ .isFilterable (false )
367+ .build ();
368+
369+ VectorStoreRecordVectorField hnswVector = VectorStoreRecordVectorField .builder ()
370+ .withName ("hnsw" )
371+ .withStorageName ("hnsw" )
372+ .withFieldType (List .class )
373+ .withDimensions (8 )
374+ .withDistanceFunction (DistanceFunction .COSINE_SIMILARITY )
375+ .withIndexKind (IndexKind .HNSW )
376+ .build ();
377+
378+ VectorStoreRecordDefinition definition = VectorStoreRecordDefinition .fromFields (
379+ Arrays .asList (keyField , dummyField , hnswVector )
380+ );
381+
382+ OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider .builder ()
383+ .withDataSource (DATA_SOURCE )
384+ .build ();
385+
386+ JDBCVectorStore vectorStore = JDBCVectorStore .builder ()
387+ .withDataSource (DATA_SOURCE )
388+ .withOptions (JDBCVectorStoreOptions .builder ()
389+ .withQueryProvider (queryProvider )
390+ .build ())
391+ .build ();
392+
393+ String collectionName = "skhotels_hnsw" ;
394+ VectorStoreRecordCollection <String , Object > collection =
395+ vectorStore .getCollection (collectionName ,
396+ JDBCVectorStoreRecordCollectionOptions .<Object >builder ()
397+ .withRecordClass (Object .class )
398+ .withRecordDefinition (definition )
399+ .build ());
400+
401+ // create collection
402+ collection .createCollectionAsync ().block ();
403+
404+ String expectedIndexName = hnswVector .getEffectiveStorageName ().toUpperCase () + "_VECTOR_INDEX" ;
405+
406+ // check if index exist
407+ try (Connection conn = DATA_SOURCE .getConnection ();
408+ PreparedStatement stmt = conn .prepareStatement (
409+ "SELECT COUNT(*) FROM USER_INDEXES WHERE INDEX_NAME=?" )) {
410+ stmt .setString (1 , expectedIndexName );
411+ ResultSet rs = stmt .executeQuery ();
412+ rs .next ();
413+ int count = rs .getInt (1 );
414+
415+ assertEquals (1 , count , "hnsw vector index should have been created" );
416+ } finally {
417+ // clean up
418+ try (Connection conn = DATA_SOURCE .getConnection ();
419+ Statement stmt = conn .createStatement ()) {
420+ stmt .executeUpdate ("DROP TABLE " + "SKCOLLECTION_" + collectionName );
421+ }
422+ }
423+ }
424+ }
425+
426+ @ Nested
427+ class UndefinedIndexTests {
428+ @ Test
429+ void testNoIndexIsCreatedForUndefined () throws Exception {
430+ // create key field
431+ VectorStoreRecordKeyField keyField = VectorStoreRecordKeyField .builder ()
432+ .withName ("id" )
433+ .withStorageName ("id" )
434+ .withFieldType (String .class )
435+ .build ();
436+
437+ // create vector field, set IndexKind to UNDEFINED
438+ VectorStoreRecordVectorField undefinedVector = VectorStoreRecordVectorField .builder ()
439+ .withName ("undef" )
440+ .withStorageName ("undef" )
441+ .withFieldType (List .class )
442+ .withDimensions (8 )
443+ .withDistanceFunction (DistanceFunction .COSINE_SIMILARITY )
444+ .withIndexKind (IndexKind .UNDEFINED )
445+ .build ();
446+
447+ VectorStoreRecordDataField dummyField = VectorStoreRecordDataField .builder ()
448+ .withName ("dummy" )
449+ .withStorageName ("dummy" )
450+ .withFieldType (String .class )
451+ .isFilterable (false )
452+ .build ();
453+
454+ VectorStoreRecordDefinition definition = VectorStoreRecordDefinition .fromFields (
455+ Arrays .asList (keyField , dummyField , undefinedVector )
456+ );
457+
458+ OracleVectorStoreQueryProvider queryProvider = OracleVectorStoreQueryProvider .builder ()
459+ .withDataSource (DATA_SOURCE )
460+ .build ();
461+
462+ JDBCVectorStore vectorStore = JDBCVectorStore .builder ()
463+ .withDataSource (DATA_SOURCE )
464+ .withOptions (JDBCVectorStoreOptions .builder ()
465+ .withQueryProvider (queryProvider )
466+ .build ())
467+ .build ();
468+
469+ String collectionName = "skhotels_undefined" ;
470+ VectorStoreRecordCollection <String , Object > collection =
471+ vectorStore .getCollection (collectionName ,
472+ JDBCVectorStoreRecordCollectionOptions .<Object >builder ()
473+ .withRecordClass (Object .class )
474+ .withRecordDefinition (definition )
475+ .build ());
476+
477+ // create collection
478+ collection .createCollectionAsync ().block ();
479+
480+ // check if index exist
481+ String expectedIndexName = undefinedVector .getEffectiveStorageName ().toUpperCase () + "_VETCOR_INDEX" ;
482+ try (Connection conn = DATA_SOURCE .getConnection ();
483+ PreparedStatement stmt = conn .prepareStatement (
484+ "SELECT COUNT(*) FROM USER_INDEXES WHERE INDEX_NAME = ?" )) {
485+ stmt .setString (1 , expectedIndexName );
486+ ResultSet rs = stmt .executeQuery ();
487+ rs .next ();
488+ int count = rs .getInt (1 );
489+
490+ assertEquals (0 ,count ,"Vector index should not be created for IndexKind.UNDEFINED" );
491+ } finally {
492+ // clean up
493+ try (Connection conn = DATA_SOURCE .getConnection ();
494+ Statement stmt = conn .createStatement ()) {
495+ stmt .executeUpdate ("DROP TABLE " + "SKCOLLECTION_" + collectionName );
496+ }
497+ }
498+ }
499+ }
500+
342501 private static Stream <Arguments > distanceFunctionAndDistance () {
343502 return Stream .of (
344503 Arguments .of (DistanceFunction .COSINE_DISTANCE , 0.8548d ),
0 commit comments