GH-3181: fix: Validate index name exists in CassandraVectorStore

Fixes: #3181

https://github.com/spring-projects/spring-ai/issues/3181

When using CassandraVectorStore with an invalid index name and
initializeSchema=false, the application would throw a generic
NoSuchElementException from Optional.get() with message "No value present"
when trying to access the index metadata.

Changes:
- Added explicit validation of index existence in checkSchemaValid() method
- Improved error handling in getIndexSimilarity() method to provide a clear
  error message when an index doesn't exist
- Added integration test to verify proper error handling with invalid index names

Signed-off-by: Soby Chacko <soby.chacko@broadcom.com>
This commit is contained in:
Soby Chacko
2025-05-15 19:37:52 -04:00
committed by Ilayaperumal Gopinathan
parent eba7bde870
commit 9eeee6178c
2 changed files with 39 additions and 5 deletions

View File

@@ -43,6 +43,7 @@ import com.datastax.oss.driver.api.core.cql.Row;
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import com.datastax.oss.driver.api.core.data.CqlVector;
import com.datastax.oss.driver.api.core.metadata.schema.ColumnMetadata;
import com.datastax.oss.driver.api.core.metadata.schema.IndexMetadata;
import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata;
import com.datastax.oss.driver.api.core.type.DataType;
import com.datastax.oss.driver.api.core.type.DataTypes;
@@ -397,11 +398,16 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme
private Similarity getIndexSimilarity(TableMetadata metadata) {
return Similarity.valueOf(metadata.getIndex(this.schema.index())
.get()
.getOptions()
.getOrDefault("similarity_function", "COSINE")
.toUpperCase());
Optional<IndexMetadata> indexMetadata = metadata.getIndex(this.schema.index());
if (indexMetadata.isEmpty()) {
throw new IllegalStateException(
String.format("Index %s does not exist in table %s", this.schema.index(), this.schema.table));
}
return Similarity
.valueOf(indexMetadata.get().getOptions().getOrDefault("similarity_function", "COSINE").toUpperCase());
}
private PreparedStatement prepareDeleteStatement() {
@@ -554,6 +560,9 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme
.getTable(this.schema.table)
.get();
Preconditions.checkState(tableMetadata.getIndex(this.schema.index()).isPresent(), "index %s does not exist",
this.schema.index());
Preconditions.checkState(tableMetadata.getColumn(this.schema.content).isPresent(), "column %s does not exist",
this.schema.content);

View File

@@ -522,6 +522,31 @@ class CassandraVectorStoreIT extends BaseVectorStoreTests {
});
}
@Test
void throwsExceptionOnInvalidIndexNameWithSchemaValidation() {
this.contextRunner.run(context -> {
// Create valid schema first, then close
try (CassandraVectorStore validStore = createTestStore(context, new SchemaColumn("meta1", DataTypes.TEXT),
new SchemaColumn("meta2", DataTypes.TEXT))) {
// Nothing to do here. This should not fail as the Schema now exists
}
// Now try with invalid index name but don't reinitialize schema
CassandraVectorStore.Builder invalidBuilder = storeBuilder(context.getBean(CqlSession.class),
context.getBean(EmbeddingModel.class))
.addMetadataColumns(new SchemaColumn("meta1", DataTypes.TEXT),
new SchemaColumn("meta2", DataTypes.TEXT))
.indexName("non_existent_index_name")
.initializeSchema(false);
IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class,
invalidBuilder::build);
assertThat(exception.getMessage()).contains("non_existent_index_name");
assertThat(exception.getMessage()).contains("does not exist");
});
}
@SpringBootConfiguration
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
public static class TestApplication {