From 50e11e3f469e893913d520393eea6bfc9bcb6aad Mon Sep 17 00:00:00 2001 From: Thomas Vitale Date: Sun, 6 Oct 2024 10:21:54 +0200 Subject: [PATCH] Improve optional values handling in vector store observations Vector store observations support several key-value pairs, coming from the Spring AI abstractions. Currently, whenever a value is not available (either because not configured by the user or not supported by the vector store provider), span/metrics attributes are generated anyway with value none. That causes several issues, including an unneeded increase in time series, challenges in alerting/monitoring (especially for integer/double attributes that suddenly are populated with a string), and non-compliance with the OpenTelemetry Semantic Conventions (according to which, attributes should be excluded altogether if there's no value). This pull request changes the conventions for vector store observations to exclude the generation of span/metrics attributes for optional values which don't have any value. Signed-off-by: Thomas Vitale --- .../VectorStoreObservationAttributes.java | 19 ++-- .../conventions/VectorStoreProvider.java | 48 +++++---- ...faultVectorStoreObservationConvention.java | 99 ++++++++----------- .../VectorStoreObservationDocumentation.java | 22 +++-- ...VectorStoreObservationConventionTests.java | 24 ++--- .../azure/AzureVectorStoreObservationIT.java | 34 ++++--- .../CassandraVectorStoreObservationIT.java | 30 +++--- .../org/springframework/ai/ChromaImage.java | 27 +++++ .../ChromaVectorStoreObservationIT.java | 25 ++--- .../ai/vectorstore/ElasticsearchImage.java | 28 ++++++ ...ElasticsearchVectorStoreObservationIT.java | 29 +++--- .../ai/vectorstore/GemFireImage.java | 27 +++++ .../GemFireVectorStoreObservationIT.java | 24 ++--- .../HanaVectorStoreObservationIT.java | 27 ++--- .../ai/vectorstore/MilvusImage.java | 27 +++++ .../MilvusVectorStoreObservationIT.java | 25 ++--- .../ai/vectorstore/MongoDbImage.java | 27 +++++ .../MongoDbVectorStoreObservationIT.java | 25 ++--- .../ai/vectorstore/Neo4jImage.java | 27 +++++ .../Neo4jVectorStoreObservationIT.java | 31 +++--- .../ai/vectorstore/OpenSearchImage.java | 27 +++++ .../OpenSearchVectorStoreObservationIT.java | 30 +++--- .../ai/vectorstore/OracleImage.java | 27 +++++ .../OracleVectorStoreObservationIT.java | 32 +++--- .../ai/vectorstore/PgVectorImage.java | 27 +++++ .../PgVectorStoreObservationIT.java | 32 +++--- .../PineconeVectorStoreObservationIT.java | 22 +++-- .../ai/vectorstore/qdrant/QdrantImage.java | 27 +++++ .../QdrantVectorStoreObservationIT.java | 28 +++--- .../ai/vectorstore/RedisVectorStore.java | 4 +- .../RedisVectorStoreObservationIT.java | 23 +++-- .../ai/vectorstore/TypesenseImage.java | 27 +++++ .../TypesenseVectorStoreObservationIT.java | 25 ++--- .../ai/vectorstore/WeaviateImage.java | 27 +++++ .../WeaviateVectorStoreObservationIT.java | 28 +++--- 35 files changed, 692 insertions(+), 319 deletions(-) create mode 100644 vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/ChromaImage.java create mode 100644 vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/ElasticsearchImage.java create mode 100644 vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/GemFireImage.java create mode 100644 vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/MilvusImage.java create mode 100644 vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/MongoDbImage.java create mode 100644 vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jImage.java create mode 100644 vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/OpenSearchImage.java create mode 100644 vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/OracleImage.java create mode 100644 vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/PgVectorImage.java create mode 100644 vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantImage.java create mode 100644 vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/TypesenseImage.java create mode 100644 vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/WeaviateImage.java diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java b/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java index 9bfada67c..bd869f0cb 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreObservationAttributes.java @@ -56,6 +56,13 @@ public enum VectorStoreObservationAttributes { */ DB_SYSTEM("db.system"), + // DB Search + + /** + * The metric used in similarity search. + */ + DB_SEARCH_SIMILARITY_METRIC("db.search.similarity_metric"), + // DB Vector /** @@ -68,11 +75,6 @@ public enum VectorStoreObservationAttributes { */ DB_VECTOR_FIELD_NAME("db.vector.field_name"), - /** - * The model used for the embedding. - */ - DB_VECTOR_MODEL("db.vector.model"), - /** * The content of the search query being executed. */ @@ -98,12 +100,7 @@ public enum VectorStoreObservationAttributes { /** * The top-k most similar vectors returned by a query. */ - DB_VECTOR_QUERY_TOP_K("db.vector.query.top_k"), - - /** - * The metric used in similarity search. - */ - DB_VECTOR_SIMILARITY_METRIC("db.vector.similarity_metric"); + DB_VECTOR_QUERY_TOP_K("db.vector.query.top_k"); private final String value; diff --git a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java b/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java index 1ae621c69..3d3d76c15 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/observation/conventions/VectorStoreProvider.java @@ -16,32 +16,42 @@ package org.springframework.ai.observation.conventions; /** + * Collection of systems providing vector store functionality. Based on the OpenTelemetry + * Semantic Conventions for Vector Databases. + * * @author Christian Tzolov + * @author Thomas Vitale * @since 1.0.0 + * @see DB + * Semantic Conventions. */ public enum VectorStoreProvider { // @formatter:off - PG_VECTOR("pg_vector"), - AZURE("azure"), - CASSANDRA("cassandra"), - CHROMA("chroma"), - ELASTICSEARCH("elasticsearch"), - MILVUS("milvus"), - NEO4J("neo4j"), - OPENSEARCH("opensearch"), - QDRANT("qdrant"), - REDIS("redis"), - TYPESENSE("typesense"), - WEAVIATE("weaviate"), - PINECONE("pinecone"), - ORACLE("oracle"), - MONGODB("mongodb"), - GEMFIRE("gemfire"), - HANA("hana"), - SIMPLE("simple"); - // @formatter:on + // Please, keep the alphabetical sorting. + AZURE("azure"), + CASSANDRA("cassandra"), + CHROMA("chroma"), + ELASTICSEARCH("elasticsearch"), + GEMFIRE("gemfire"), + HANA("hana"), + MILVUS("milvus"), + MONGODB("mongodb"), + NEO4J("neo4j"), + OPENSEARCH("opensearch"), + ORACLE("oracle"), + PG_VECTOR("pg_vector"), + PINECONE("pinecone"), + QDRANT("qdrant"), + REDIS("redis"), + SIMPLE("simple"), + TYPESENSE("typesense"), + WEAVIATE("weaviate"); + + // @formatter:on + private final String value; VectorStoreProvider(String value) { diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConvention.java b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConvention.java index 246f1c2f4..cfddd211c 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConvention.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConvention.java @@ -35,33 +35,6 @@ public class DefaultVectorStoreObservationConvention implements VectorStoreObser public static final String DEFAULT_NAME = "db.vector.client.operation"; - private static final KeyValue COLLECTION_NAME_NONE = KeyValue.of(HighCardinalityKeyNames.DB_COLLECTION_NAME, - KeyValue.NONE_VALUE); - - private static final KeyValue DIMENSIONS_NONE = KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT, - KeyValue.NONE_VALUE); - - private static final KeyValue METADATA_FILTER_NONE = KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_FILTER, - KeyValue.NONE_VALUE); - - private static final KeyValue FIELD_NAME_NONE = KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME, - KeyValue.NONE_VALUE); - - private static final KeyValue NAMESPACE_NONE = KeyValue.of(HighCardinalityKeyNames.DB_NAMESPACE, - KeyValue.NONE_VALUE); - - private static final KeyValue QUERY_CONTENT_NONE = KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT, - KeyValue.NONE_VALUE); - - private static final KeyValue SIMILARITY_METRIC_NONE = KeyValue - .of(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC, KeyValue.NONE_VALUE); - - private static final KeyValue SIMILARITY_THRESHOLD_NONE = KeyValue - .of(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD, KeyValue.NONE_VALUE); - - private static final KeyValue TOP_K_NONE = KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K, - KeyValue.NONE_VALUE); - private final String name; public DefaultVectorStoreObservationConvention() { @@ -102,74 +75,86 @@ public class DefaultVectorStoreObservationConvention implements VectorStoreObser @Override public KeyValues getHighCardinalityKeyValues(VectorStoreObservationContext context) { - return KeyValues.of(collectionName(context), dimensions(context), fieldName(context), metadataFilter(context), - namespace(context), queryContent(context), similarityMetric(context), similarityThreshold(context), - topK(context)); + var keyValues = KeyValues.empty(); + keyValues = collectionName(keyValues, context); + keyValues = dimensions(keyValues, context); + keyValues = fieldName(keyValues, context); + keyValues = metadataFilter(keyValues, context); + keyValues = namespace(keyValues, context); + keyValues = queryContent(keyValues, context); + keyValues = similarityMetric(keyValues, context); + keyValues = similarityThreshold(keyValues, context); + keyValues = topK(keyValues, context); + return keyValues; } - protected KeyValue collectionName(VectorStoreObservationContext context) { + protected KeyValues collectionName(KeyValues keyValues, VectorStoreObservationContext context) { if (StringUtils.hasText(context.getCollectionName())) { - return KeyValue.of(HighCardinalityKeyNames.DB_COLLECTION_NAME, context.getCollectionName()); + return keyValues.and(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), context.getCollectionName()); } - return COLLECTION_NAME_NONE; + return keyValues; } - protected KeyValue dimensions(VectorStoreObservationContext context) { + protected KeyValues dimensions(KeyValues keyValues, VectorStoreObservationContext context) { if (context.getDimensions() != null && context.getDimensions() > 0) { - return KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT, "" + context.getDimensions()); + return keyValues.and(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), + "" + context.getDimensions()); } - return DIMENSIONS_NONE; + return keyValues; } - protected KeyValue fieldName(VectorStoreObservationContext context) { + protected KeyValues fieldName(KeyValues keyValues, VectorStoreObservationContext context) { if (StringUtils.hasText(context.getFieldName())) { - return KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME, context.getFieldName()); + return keyValues.and(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), context.getFieldName()); } - return FIELD_NAME_NONE; + return keyValues; } - protected KeyValue metadataFilter(VectorStoreObservationContext context) { + protected KeyValues metadataFilter(KeyValues keyValues, VectorStoreObservationContext context) { if (context.getQueryRequest() != null && context.getQueryRequest().getFilterExpression() != null) { - return KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_FILTER, + return keyValues.and(HighCardinalityKeyNames.DB_VECTOR_QUERY_FILTER.asString(), context.getQueryRequest().getFilterExpression().toString()); } - return METADATA_FILTER_NONE; + return keyValues; } - protected KeyValue namespace(VectorStoreObservationContext context) { + protected KeyValues namespace(KeyValues keyValues, VectorStoreObservationContext context) { if (StringUtils.hasText(context.getNamespace())) { - return KeyValue.of(HighCardinalityKeyNames.DB_NAMESPACE, context.getNamespace()); + return keyValues.and(HighCardinalityKeyNames.DB_NAMESPACE.asString(), context.getNamespace()); } - return NAMESPACE_NONE; + return keyValues; } - protected KeyValue queryContent(VectorStoreObservationContext context) { + protected KeyValues queryContent(KeyValues keyValues, VectorStoreObservationContext context) { if (context.getQueryRequest() != null && StringUtils.hasText(context.getQueryRequest().getQuery())) { - return KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT, context.getQueryRequest().getQuery()); + return keyValues.and(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), + context.getQueryRequest().getQuery()); } - return QUERY_CONTENT_NONE; + return keyValues; } - protected KeyValue similarityMetric(VectorStoreObservationContext context) { + protected KeyValues similarityMetric(KeyValues keyValues, VectorStoreObservationContext context) { if (StringUtils.hasText(context.getSimilarityMetric())) { - return KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC, context.getSimilarityMetric()); + return keyValues.and(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + context.getSimilarityMetric()); } - return SIMILARITY_METRIC_NONE; + return keyValues; } - protected KeyValue similarityThreshold(VectorStoreObservationContext context) { + protected KeyValues similarityThreshold(KeyValues keyValues, VectorStoreObservationContext context) { if (context.getQueryRequest() != null && context.getQueryRequest().getSimilarityThreshold() >= 0) { - return KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD, + return keyValues.and(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), String.valueOf(context.getQueryRequest().getSimilarityThreshold())); } - return SIMILARITY_THRESHOLD_NONE; + return keyValues; } - protected KeyValue topK(VectorStoreObservationContext context) { + protected KeyValues topK(KeyValues keyValues, VectorStoreObservationContext context) { if (context.getQueryRequest() != null && context.getQueryRequest().getTopK() > 0) { - return KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K, "" + context.getQueryRequest().getTopK()); + return keyValues.and(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), + "" + context.getQueryRequest().getTopK()); } - return TOP_K_NONE; + return keyValues; } } diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationDocumentation.java b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationDocumentation.java index 20996ec2b..f56ead4de 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationDocumentation.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/VectorStoreObservationDocumentation.java @@ -116,6 +116,18 @@ public enum VectorStoreObservationDocumentation implements ObservationDocumentat } }, + // DB Search + + /** + * The metric used in similarity search. + */ + DB_SEARCH_SIMILARITY_METRIC { + @Override + public String asString() { + return VectorStoreObservationAttributes.DB_SEARCH_SIMILARITY_METRIC.value(); + } + }, + // DB Vector /** @@ -188,16 +200,6 @@ public enum VectorStoreObservationDocumentation implements ObservationDocumentat public String asString() { return VectorStoreObservationAttributes.DB_VECTOR_QUERY_TOP_K.value(); } - }, - - /** - * The metric used in similarity search. - */ - DB_VECTOR_SIMILARITY_METRIC { - @Override - public String asString() { - return VectorStoreObservationAttributes.DB_VECTOR_SIMILARITY_METRIC.value(); - } }; } diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java b/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java index 00e33e517..5882f9285 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/observation/DefaultVectorStoreObservationConventionTests.java @@ -68,13 +68,13 @@ class DefaultVectorStoreObservationConventionTests { .builder("my_database", VectorStoreObservationContext.Operation.QUERY) .build(); assertThat(this.observationConvention.getLowCardinalityKeyValues(observationContext)).contains( + KeyValue.of(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()), KeyValue.of(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query"), KeyValue.of(LowCardinalityKeyNames.DB_SYSTEM.asString(), "my_database")); } @Test void shouldHaveOptionalKeyValues() { - VectorStoreObservationContext observationContext = VectorStoreObservationContext .builder("my-database", VectorStoreObservationContext.Operation.QUERY) .withCollectionName("COLLECTION_NAME") @@ -102,26 +102,28 @@ class DefaultVectorStoreObservationConventionTests { KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "696"), KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "FIELD_NAME"), KeyValue.of(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "NAMESPACE"), - KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "SIMILARITY_METRIC"), + KeyValue.of(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), "SIMILARITY_METRIC"), KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "VDB QUERY"), KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_FILTER.asString(), "Expression[type=AND, left=Expression[type=EQ, left=Key[key=country], right=Value[value=UK]], right=Expression[type=GTE, left=Key[key=year], right=Value[value=2020]]]")); } @Test - void shouldHaveMissingKeyValues() { + void shouldNotHaveKeyValuesWhenMissing() { VectorStoreObservationContext observationContext = VectorStoreObservationContext .builder("my-database", VectorStoreObservationContext.Operation.QUERY) .build(); - assertThat(this.observationConvention.getHighCardinalityKeyValues(observationContext)).contains( - KeyValue.of(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), KeyValue.NONE_VALUE), - KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), KeyValue.NONE_VALUE), - KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), KeyValue.NONE_VALUE), - KeyValue.of(HighCardinalityKeyNames.DB_NAMESPACE.asString(), KeyValue.NONE_VALUE), - KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), KeyValue.NONE_VALUE), - KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), KeyValue.NONE_VALUE), - KeyValue.of(HighCardinalityKeyNames.DB_VECTOR_QUERY_FILTER.asString(), KeyValue.NONE_VALUE)); + assertThat(this.observationConvention.getHighCardinalityKeyValues(observationContext) + .stream() + .map(KeyValue::getKey) + .toList()).doesNotContain(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), + HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), + HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), + HighCardinalityKeyNames.DB_NAMESPACE.asString(), + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), + HighCardinalityKeyNames.DB_VECTOR_QUERY_FILTER.asString()); } } diff --git a/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreObservationIT.java b/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreObservationIT.java index 72f6c8129..10c876db0 100644 --- a/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreObservationIT.java @@ -32,6 +32,8 @@ import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.observation.conventions.SpringAiKind; +import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; @@ -104,21 +106,23 @@ public class AzureVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("azure add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.AZURE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") - .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), "azure") + .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), + VectorStoreProvider.AZURE.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), AzureVectorStore.DEFAULT_INDEX_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -134,9 +138,10 @@ public class AzureVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("azure query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.AZURE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") - .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), "azure") + .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), + VectorStoreProvider.AZURE.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) @@ -145,9 +150,10 @@ public class AzureVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), AzureVectorStore.DEFAULT_INDEX_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/CassandraVectorStoreObservationIT.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/CassandraVectorStoreObservationIT.java index 1e3ac241e..43f650022 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/CassandraVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/CassandraVectorStoreObservationIT.java @@ -27,6 +27,8 @@ import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.observation.conventions.SpringAiKind; +import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.CassandraVectorStoreConfig.SchemaColumn; import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention; @@ -95,21 +97,23 @@ public class CassandraVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("cassandra add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.CASSANDRA.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") - .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), "cassandra") + .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), + VectorStoreProvider.CASSANDRA.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), CassandraVectorStoreConfig.DEFAULT_TABLE_NAME) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "test_springframework") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -125,9 +129,10 @@ public class CassandraVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("cassandra query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.CASSANDRA.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") - .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), "cassandra") + .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), + VectorStoreProvider.CASSANDRA.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) @@ -137,8 +142,9 @@ public class CassandraVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), CassandraVectorStoreConfig.DEFAULT_TABLE_NAME) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "test_springframework") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/ChromaImage.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/ChromaImage.java new file mode 100644 index 000000000..9cbbaa4a4 --- /dev/null +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/ChromaImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class ChromaImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("ghcr.io/chroma-core/chroma:0.5.11"); + +} diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/vectorstore/ChromaVectorStoreObservationIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/vectorstore/ChromaVectorStoreObservationIT.java index 120485514..89e9eab2e 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/vectorstore/ChromaVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/vectorstore/ChromaVectorStoreObservationIT.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; +import org.springframework.ai.ChromaImage; import org.springframework.ai.chroma.ChromaApi; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; @@ -57,7 +58,7 @@ import io.micrometer.observation.tck.TestObservationRegistryAssert; public class ChromaVectorStoreObservationIT { @Container - static ChromaDBContainer chromaContainer = new ChromaDBContainer("ghcr.io/chroma-core/chroma:0.5.0"); + static ChromaDBContainer chromaContainer = new ChromaDBContainer(ChromaImage.DEFAULT_IMAGE); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withUserConfiguration(Config.class); @@ -92,22 +93,23 @@ public class ChromaVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("chroma add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.CHROMA.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.CHROMA.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), "TestCollection:" + vectorStore.getCollectionId()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "distance") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -123,7 +125,7 @@ public class ChromaVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("chroma query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.CHROMA.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.CHROMA.value()) @@ -135,9 +137,10 @@ public class ChromaVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), "TestCollection:" + vectorStore.getCollectionId()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "distance") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/ElasticsearchImage.java b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/ElasticsearchImage.java new file mode 100644 index 000000000..2697c1950 --- /dev/null +++ b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/ElasticsearchImage.java @@ -0,0 +1,28 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class ElasticsearchImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName + .parse("docker.elastic.co/elasticsearch/elasticsearch:8.15.2"); + +} diff --git a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/ElasticsearchVectorStoreObservationIT.java b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/ElasticsearchVectorStoreObservationIT.java index e6bb89b99..4a0c9cc58 100644 --- a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/ElasticsearchVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/ElasticsearchVectorStoreObservationIT.java @@ -36,6 +36,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.observation.conventions.SpringAiKind; import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.openai.OpenAiEmbeddingModel; import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention; @@ -73,7 +74,7 @@ public class ElasticsearchVectorStoreObservationIT { @Container private static final ElasticsearchContainer elasticsearchContainer = new ElasticsearchContainer( - "docker.elastic.co/elasticsearch/elasticsearch:8.13.3") + ElasticsearchImage.DEFAULT_IMAGE) .withEnv("xpack.security.enabled", "false"); List documents = List.of( @@ -129,22 +130,23 @@ public class ElasticsearchVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("elasticsearch add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.ELASTICSEARCH.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.ELASTICSEARCH.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), "spring-ai-document-index") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -165,7 +167,7 @@ public class ElasticsearchVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("elasticsearch query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.ELASTICSEARCH.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.ELASTICSEARCH.value()) @@ -177,9 +179,10 @@ public class ElasticsearchVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), "spring-ai-document-index") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/GemFireImage.java b/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/GemFireImage.java new file mode 100644 index 000000000..806497e25 --- /dev/null +++ b/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/GemFireImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class GemFireImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("gemfire/gemfire-all:10.1-jdk17"); + +} diff --git a/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/GemFireVectorStoreObservationIT.java b/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/GemFireVectorStoreObservationIT.java index 6fb44d385..5cdd50591 100644 --- a/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/GemFireVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/GemFireVectorStoreObservationIT.java @@ -80,7 +80,7 @@ public class GemFireVectorStoreObservationIT { Ports.Binding hostPort = Ports.Binding.bindPort(HTTP_SERVICE_PORT); ExposedPort exposedPort = new ExposedPort(HTTP_SERVICE_PORT); PortBinding mappedPort = new PortBinding(hostPort, exposedPort); - gemFireCluster = new GemFireCluster("gemfire/gemfire-all:10.1-jdk17", LOCATOR_COUNT, SERVER_COUNT); + gemFireCluster = new GemFireCluster(GemFireImage.DEFAULT_IMAGE, LOCATOR_COUNT, SERVER_COUNT); gemFireCluster.withConfiguration(GemFireCluster.SERVER_GLOB, container -> container.withExposedPorts(HTTP_SERVICE_PORT) .withCreateContainerCmdModifier(cmd -> cmd.getHostConfig().withPortBindings(mappedPort))); @@ -125,21 +125,22 @@ public class GemFireVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("gemfire add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.GEMFIRE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.GEMFIRE.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), TEST_INDEX_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "/embeddings") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -161,7 +162,7 @@ public class GemFireVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("gemfire query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.GEMFIRE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.GEMFIRE.value()) @@ -172,9 +173,10 @@ public class GemFireVectorStoreObservationIT { "What is Great Depression") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), TEST_INDEX_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "/embeddings") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/HanaVectorStoreObservationIT.java b/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/HanaVectorStoreObservationIT.java index 6f654b591..78c324a4d 100644 --- a/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/HanaVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/HanaVectorStoreObservationIT.java @@ -30,6 +30,7 @@ import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.observation.conventions.SpringAiKind; import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.openai.OpenAiEmbeddingModel; import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention; @@ -94,21 +95,22 @@ public class HanaVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("hana add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.HANA.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.HANA.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), TEST_TABLE_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -124,7 +126,7 @@ public class HanaVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("hana query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.HANA.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.HANA.value()) @@ -135,9 +137,10 @@ public class HanaVectorStoreObservationIT { "What is Great Depression") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), TEST_TABLE_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/MilvusImage.java b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/MilvusImage.java new file mode 100644 index 000000000..ffdcd3c4b --- /dev/null +++ b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/MilvusImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class MilvusImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("milvusdb/milvus:v2.4.9"); + +} diff --git a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/MilvusVectorStoreObservationIT.java b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/MilvusVectorStoreObservationIT.java index a0c351451..4abca7875 100644 --- a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/MilvusVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/vectorstore/MilvusVectorStoreObservationIT.java @@ -28,6 +28,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.observation.conventions.SpringAiKind; import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.openai.OpenAiEmbeddingModel; import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.ai.vectorstore.MilvusVectorStore.MilvusVectorStoreConfig; @@ -61,7 +62,7 @@ public class MilvusVectorStoreObservationIT { private static final String TEST_COLLECTION_NAME = "test_vector_store"; @Container - private static MilvusContainer milvusContainer = new MilvusContainer("milvusdb/milvus:v2.3.8"); + private static MilvusContainer milvusContainer = new MilvusContainer(MilvusImage.DEFAULT_IMAGE); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withUserConfiguration(Config.class); @@ -96,21 +97,22 @@ public class MilvusVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("milvus add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.MILVUS.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.MILVUS.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), TEST_COLLECTION_NAME) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "default") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -126,7 +128,7 @@ public class MilvusVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("milvus query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.MILVUS.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.MILVUS.value()) @@ -138,8 +140,9 @@ public class MilvusVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), TEST_COLLECTION_NAME) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "default") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/MongoDbImage.java b/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/MongoDbImage.java new file mode 100644 index 000000000..ed59c4993 --- /dev/null +++ b/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/MongoDbImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class MongoDbImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("mongodb/mongodb-atlas-local:8.0.0"); + +} diff --git a/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/MongoDbVectorStoreObservationIT.java b/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/MongoDbVectorStoreObservationIT.java index f69c55788..3c78d31ea 100644 --- a/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/MongoDbVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/MongoDbVectorStoreObservationIT.java @@ -69,8 +69,7 @@ import org.testcontainers.mongodb.MongoDBAtlasLocalContainer; public class MongoDbVectorStoreObservationIT { @Container - private static MongoDBAtlasLocalContainer container = new MongoDBAtlasLocalContainer( - "mongodb/mongodb-atlas-local:7.0.9"); + private static MongoDBAtlasLocalContainer container = new MongoDBAtlasLocalContainer(MongoDbImage.DEFAULT_IMAGE); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withUserConfiguration(Config.class) @@ -117,22 +116,23 @@ public class MongoDbVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("mongodb add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.MONGODB.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.MONGODB.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), MongoDBAtlasVectorStore.DEFAULT_VECTOR_COLLECTION_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "embedding") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -148,7 +148,7 @@ public class MongoDbVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("mongodb query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.MONGODB.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.MONGODB.value()) @@ -160,9 +160,10 @@ public class MongoDbVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), MongoDBAtlasVectorStore.DEFAULT_VECTOR_COLLECTION_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "embedding") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jImage.java b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jImage.java new file mode 100644 index 000000000..e64012b76 --- /dev/null +++ b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class Neo4jImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("neo4j:5.24"); + +} diff --git a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jVectorStoreObservationIT.java b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jVectorStoreObservationIT.java index 4f0b7bcd7..ebf09454d 100644 --- a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jVectorStoreObservationIT.java @@ -34,6 +34,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.observation.conventions.SpringAiKind; import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.openai.OpenAiEmbeddingModel; import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention; @@ -48,7 +49,6 @@ import org.springframework.core.io.DefaultResourceLoader; import org.testcontainers.containers.Neo4jContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistry; @@ -63,8 +63,7 @@ import io.micrometer.observation.tck.TestObservationRegistryAssert; public class Neo4jVectorStoreObservationIT { @Container - static Neo4jContainer neo4jContainer = new Neo4jContainer<>(DockerImageName.parse("neo4j:5.18")) - .withRandomPassword(); + static Neo4jContainer neo4jContainer = new Neo4jContainer<>(Neo4jImage.DEFAULT_IMAGE).withRandomPassword(); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withUserConfiguration(Config.class); @@ -105,22 +104,23 @@ public class Neo4jVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("neo4j add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.NEO4J.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.NEO4J.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), SchemaNames.sanitize(Neo4jVectorStore.DEFAULT_INDEX_NAME).orElseThrow()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -136,7 +136,7 @@ public class Neo4jVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("neo4j query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.NEO4J.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.NEO4J.value()) @@ -148,9 +148,10 @@ public class Neo4jVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), SchemaNames.sanitize(Neo4jVectorStore.DEFAULT_INDEX_NAME).orElseThrow()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/OpenSearchImage.java b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/OpenSearchImage.java new file mode 100644 index 000000000..dea664624 --- /dev/null +++ b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/OpenSearchImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class OpenSearchImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("opensearchproject/opensearch:2.17.1"); + +} diff --git a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/OpenSearchVectorStoreObservationIT.java b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/OpenSearchVectorStoreObservationIT.java index 5e3faed1c..45298605d 100644 --- a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/OpenSearchVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/OpenSearchVectorStoreObservationIT.java @@ -39,6 +39,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.observation.conventions.SpringAiKind; import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.openai.OpenAiEmbeddingModel; import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention; @@ -52,7 +53,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.core.io.DefaultResourceLoader; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.utility.DockerImageName; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.tck.TestObservationRegistry; @@ -70,7 +70,7 @@ public class OpenSearchVectorStoreObservationIT { @Container private static final OpensearchContainer opensearchContainer = new OpensearchContainer<>( - DockerImageName.parse("opensearchproject/opensearch:2.13.0")); + OpenSearchImage.DEFAULT_IMAGE); List documents = List.of( new Document(getText("classpath:/test/data/spring.ai.txt"), Map.of("meta1", "meta1")), @@ -121,22 +121,23 @@ public class OpenSearchVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("opensearch add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.OPENSEARCH.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.OPENSEARCH.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), OpenSearchVectorStore.DEFAULT_INDEX_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -156,7 +157,7 @@ public class OpenSearchVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("opensearch query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.OPENSEARCH.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.OPENSEARCH.value()) @@ -168,9 +169,10 @@ public class OpenSearchVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), OpenSearchVectorStore.DEFAULT_INDEX_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/OracleImage.java b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/OracleImage.java new file mode 100644 index 000000000..3f2250a3c --- /dev/null +++ b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/OracleImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class OracleImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("gvenzl/oracle-free:23-slim"); + +} diff --git a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/OracleVectorStoreObservationIT.java b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/OracleVectorStoreObservationIT.java index 534e026b7..8d2636fbf 100644 --- a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/OracleVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/OracleVectorStoreObservationIT.java @@ -30,6 +30,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.observation.conventions.SpringAiKind; import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.OracleVectorStore.OracleVectorStoreDistanceType; import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention; @@ -64,9 +65,8 @@ import oracle.jdbc.pool.OracleDataSource; public class OracleVectorStoreObservationIT { @Container - static OracleContainer oracle23aiContainer = new OracleContainer("gvenzl/oracle-free:23-slim") - .withCopyFileToContainer(MountableFile.forClasspathResource("/initialize.sql"), - "/container-entrypoint-initdb.d/initialize.sql"); + static OracleContainer oracle23aiContainer = new OracleContainer(OracleImage.DEFAULT_IMAGE).withCopyFileToContainer( + MountableFile.forClasspathResource("/initialize.sql"), "/container-entrypoint-initdb.d/initialize.sql"); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withUserConfiguration(Config.class) @@ -112,22 +112,23 @@ public class OracleVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("oracle add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.ORACLE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.ORACLE.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), OracleVectorStore.DEFAULT_TABLE_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -143,7 +144,7 @@ public class OracleVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("oracle query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.ORACLE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.ORACLE.value()) @@ -155,9 +156,10 @@ public class OracleVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), OracleVectorStore.DEFAULT_TABLE_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/PgVectorImage.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/PgVectorImage.java new file mode 100644 index 000000000..5e4204cdb --- /dev/null +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/PgVectorImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class PgVectorImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("pgvector/pgvector:pg17"); + +} diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/PgVectorStoreObservationIT.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/PgVectorStoreObservationIT.java index 1f1563318..f60b66b49 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/PgVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/PgVectorStoreObservationIT.java @@ -29,6 +29,8 @@ import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.observation.conventions.SpringAiKind; +import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.openai.OpenAiEmbeddingModel; import org.springframework.ai.openai.api.OpenAiApi; @@ -69,7 +71,7 @@ public class PgVectorStoreObservationIT { @Container @SuppressWarnings("resource") - static PostgreSQLContainer postgresContainer = new PostgreSQLContainer<>("pgvector/pgvector:pg16") + static PostgreSQLContainer postgresContainer = new PostgreSQLContainer<>(PgVectorImage.DEFAULT_IMAGE) .withUsername("postgres") .withPassword("postgres"); @@ -113,21 +115,23 @@ public class PgVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("pg_vector add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.PG_VECTOR.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") - .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), "pg_vector") + .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), + VectorStoreProvider.PG_VECTOR.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1536") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), PgVectorStore.DEFAULT_TABLE_NAME) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "public") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -143,9 +147,10 @@ public class PgVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("pg_vector query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.PG_VECTOR.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") - .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), "pg_vector") + .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), + VectorStoreProvider.PG_VECTOR.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) @@ -155,8 +160,9 @@ public class PgVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), PgVectorStore.DEFAULT_TABLE_NAME) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "public") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreObservationIT.java b/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreObservationIT.java index ee64e809e..8fc6b41f7 100644 --- a/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreObservationIT.java @@ -107,21 +107,22 @@ public class PineconeVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("pinecone add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.PINECONE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.PINECONE.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), PINECONE_INDEX_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "article") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -141,7 +142,7 @@ public class PineconeVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("pinecone query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.PINECONE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.PINECONE.value()) @@ -152,9 +153,10 @@ public class PineconeVectorStoreObservationIT { "What is Great Depression") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), PINECONE_INDEX_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "article") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantImage.java b/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantImage.java new file mode 100644 index 000000000..4a6592ffa --- /dev/null +++ b/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore.qdrant; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class QdrantImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("qdrant/qdrant:v1.9.7"); + +} diff --git a/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreObservationIT.java b/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreObservationIT.java index 0dbf67657..5d181cf03 100644 --- a/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreObservationIT.java @@ -68,7 +68,7 @@ public class QdrantVectorStoreObservationIT { private static final int EMBEDDING_DIMENSION = 1024; @Container - static QdrantContainer qdrantContainer = new QdrantContainer("qdrant/qdrant:v1.9.2"); + static QdrantContainer qdrantContainer = new QdrantContainer(QdrantImage.DEFAULT_IMAGE); List documents = List.of( new Document(getText("classpath:/test/data/spring.ai.txt"), Map.of("meta1", "meta1")), @@ -118,21 +118,22 @@ public class QdrantVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("qdrant add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.QDRANT.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.QDRANT.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1024") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), COLLECTION_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -148,7 +149,7 @@ public class QdrantVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("qdrant query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.QDRANT.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.QDRANT.value()) @@ -159,9 +160,10 @@ public class QdrantVectorStoreObservationIT { "What is Great Depression") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "1024") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), COLLECTION_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/RedisVectorStore.java b/vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/RedisVectorStore.java index 943b31e1a..d6c7c6808 100644 --- a/vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/RedisVectorStore.java +++ b/vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/RedisVectorStore.java @@ -35,6 +35,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.EmbeddingOptionsBuilder; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.vectorstore.filter.FilterExpressionConverter; import org.springframework.ai.vectorstore.observation.AbstractObservationVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; @@ -491,7 +492,8 @@ public class RedisVectorStore extends AbstractObservationVectorStore implements .withCollectionName(this.config.indexName) .withDimensions(this.embeddingModel.dimensions()) .withFieldName(this.config.embeddingFieldName) - .withSimilarityMetric(vectorAlgorithm().name()); + .withSimilarityMetric( + "COSINE".equals(DEFAULT_DISTANCE_METRIC) ? VectorStoreSimilarityMetric.COSINE.value() : ""); } diff --git a/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/RedisVectorStoreObservationIT.java b/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/RedisVectorStoreObservationIT.java index 2a7b717bf..64b30ce05 100644 --- a/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/RedisVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/RedisVectorStoreObservationIT.java @@ -29,6 +29,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.observation.conventions.SpringAiKind; import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.RedisVectorStore.MetadataField; import org.springframework.ai.vectorstore.RedisVectorStore.RedisVectorStoreConfig; @@ -104,22 +105,23 @@ public class RedisVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("redis add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.REDIS.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.REDIS.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), RedisVectorStore.DEFAULT_INDEX_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "embedding") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "HNSW") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -135,7 +137,7 @@ public class RedisVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("redis query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.REDIS.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.REDIS.value()) @@ -147,9 +149,10 @@ public class RedisVectorStoreObservationIT { .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), RedisVectorStore.DEFAULT_INDEX_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "embedding") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "HNSW") + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/TypesenseImage.java b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/TypesenseImage.java new file mode 100644 index 000000000..ac27de2a8 --- /dev/null +++ b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/TypesenseImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class TypesenseImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("typesense/typesense:27.1"); + +} diff --git a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/TypesenseVectorStoreObservationIT.java b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/TypesenseVectorStoreObservationIT.java index 47d35b40d..c5fdc8810 100644 --- a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/TypesenseVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/TypesenseVectorStoreObservationIT.java @@ -30,6 +30,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.observation.conventions.SpringAiKind; import org.springframework.ai.observation.conventions.VectorStoreProvider; +import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric; import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.TypesenseVectorStore.TypesenseVectorStoreConfig; import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention; @@ -61,7 +62,7 @@ public class TypesenseVectorStoreObservationIT { private static final String TEST_COLLECTION_NAME = "test_vector_store"; @Container - private static GenericContainer typesenseContainer = new GenericContainer<>("typesense/typesense:26.0") + private static GenericContainer typesenseContainer = new GenericContainer<>(TypesenseImage.DEFAULT_IMAGE) .withExposedPorts(8108) .withCommand("--data-dir", "/tmp", "--api-key=xyz", "--enable-cors"); @@ -98,21 +99,22 @@ public class TypesenseVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("typesense add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.TYPESENSE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.TYPESENSE.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), TEST_COLLECTION_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "embedding") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -128,7 +130,7 @@ public class TypesenseVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("typesense query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.TYPESENSE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.TYPESENSE.value()) @@ -139,9 +141,10 @@ public class TypesenseVectorStoreObservationIT { "What is Great Depression") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), TEST_COLLECTION_NAME) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "embedding") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "cosine") + .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString(), + VectorStoreSimilarityMetric.COSINE.value()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0") diff --git a/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/WeaviateImage.java b/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/WeaviateImage.java new file mode 100644 index 000000000..81e78bc5c --- /dev/null +++ b/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/WeaviateImage.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.vectorstore; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public class WeaviateImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("semitechnologies/weaviate:1.25.9"); + +} diff --git a/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/WeaviateVectorStoreObservationIT.java b/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/WeaviateVectorStoreObservationIT.java index 20d04a97d..35f9c4d59 100644 --- a/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/WeaviateVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/WeaviateVectorStoreObservationIT.java @@ -56,7 +56,7 @@ import io.weaviate.client.WeaviateClient; public class WeaviateVectorStoreObservationIT { @Container - static WeaviateContainer weaviateContainer = new WeaviateContainer("semitechnologies/weaviate:1.25.4") + static WeaviateContainer weaviateContainer = new WeaviateContainer(WeaviateImage.DEFAULT_IMAGE) .waitingFor(Wait.forHttp("/v1/.well-known/ready").forPort(8080)); List documents = List.of( @@ -92,21 +92,22 @@ public class WeaviateVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("weaviate add") + .hasContextualNameEqualTo("%s add".formatted(VectorStoreProvider.WEAVIATE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "add") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.WEAVIATE.value()) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.SPRING_AI_KIND.asString(), SpringAiKind.VECTOR_STORE.value()) - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_CONTENT.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), "SpringAiWeaviate") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), - "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString()) .hasBeenStarted() .hasBeenStopped(); @@ -122,7 +123,7 @@ public class WeaviateVectorStoreObservationIT { .doesNotHaveAnyRemainingCurrentObservation() .hasObservationWithNameEqualTo(DefaultVectorStoreObservationConvention.DEFAULT_NAME) .that() - .hasContextualNameEqualTo("weaviate query") + .hasContextualNameEqualTo("%s query".formatted(VectorStoreProvider.WEAVIATE.value())) .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_OPERATION_NAME.asString(), "query") .hasLowCardinalityKeyValue(LowCardinalityKeyNames.DB_SYSTEM.asString(), VectorStoreProvider.WEAVIATE.value()) @@ -133,9 +134,10 @@ public class WeaviateVectorStoreObservationIT { "What is Great Depression") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_DIMENSION_COUNT.asString(), "384") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_COLLECTION_NAME.asString(), "SpringAiWeaviate") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_NAMESPACE.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString(), "none") - .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_SIMILARITY_METRIC.asString(), "none") + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_NAMESPACE.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey(HighCardinalityKeyNames.DB_VECTOR_FIELD_NAME.asString()) + .doesNotHaveHighCardinalityKeyValueWithKey( + HighCardinalityKeyNames.DB_SEARCH_SIMILARITY_METRIC.asString()) .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_TOP_K.asString(), "1") .hasHighCardinalityKeyValue(HighCardinalityKeyNames.DB_VECTOR_QUERY_SIMILARITY_THRESHOLD.asString(), "0.0")