diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreAutoConfiguration.java index 0c65588cbec..f13d2998b33 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreAutoConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; -import org.springframework.ai.vectorstore.Neo4jVectorStore; +import org.springframework.ai.neo4j.vectorstore.Neo4jVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -57,20 +57,23 @@ public Neo4jVectorStore vectorStore(Driver driver, EmbeddingModel embeddingModel Neo4jVectorStoreProperties properties, ObjectProvider observationRegistry, ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - Neo4jVectorStore.Neo4jVectorStoreConfig config = Neo4jVectorStore.Neo4jVectorStoreConfig.builder() - .withDatabaseName(properties.getDatabaseName()) - .withEmbeddingDimension(properties.getEmbeddingDimension()) - .withDistanceType(properties.getDistanceType()) - .withLabel(properties.getLabel()) - .withEmbeddingProperty(properties.getEmbeddingProperty()) - .withIndexName(properties.getIndexName()) - .withIdProperty(properties.getIdProperty()) - .withConstraintName(properties.getConstraintName()) - .build(); - return new Neo4jVectorStore(driver, embeddingModel, config, properties.isInitializeSchema(), - observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP), - customObservationConvention.getIfAvailable(() -> null), batchingStrategy); + return Neo4jVectorStore.builder() + .driver(driver) + .embeddingModel(embeddingModel) + .initializeSchema(properties.isInitializeSchema()) + .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) + .customObservationConvention(customObservationConvention.getIfAvailable(() -> null)) + .batchingStrategy(batchingStrategy) + .databaseName(properties.getDatabaseName()) + .embeddingDimension(properties.getEmbeddingDimension()) + .distanceType(properties.getDistanceType()) + .label(properties.getLabel()) + .embeddingProperty(properties.getEmbeddingProperty()) + .indexName(properties.getIndexName()) + .idProperty(properties.getIdProperty()) + .constraintName(properties.getConstraintName()) + .build(); } } diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreProperties.java index b6a4f154744..232e85f163d 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreProperties.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreProperties.java @@ -17,7 +17,7 @@ package org.springframework.ai.autoconfigure.vectorstore.neo4j; import org.springframework.ai.autoconfigure.vectorstore.CommonVectorStoreProperties; -import org.springframework.ai.vectorstore.Neo4jVectorStore; +import org.springframework.ai.neo4j.vectorstore.Neo4jVectorStore; import org.springframework.boot.context.properties.ConfigurationProperties; /** diff --git a/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/Neo4jVectorStore.java b/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/neo4j/vectorstore/Neo4jVectorStore.java similarity index 62% rename from vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/Neo4jVectorStore.java rename to vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/neo4j/vectorstore/Neo4jVectorStore.java index 989084504ee..ac8a97dab7b 100644 --- a/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/Neo4jVectorStore.java +++ b/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/neo4j/vectorstore/Neo4jVectorStore.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.vectorstore; +package org.springframework.ai.neo4j.vectorstore; import java.util.HashMap; import java.util.List; @@ -36,12 +36,15 @@ 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.Neo4jVectorFilterExpressionConverter; +import org.springframework.ai.vectorstore.AbstractVectorStoreBuilder; +import org.springframework.ai.vectorstore.SearchRequest; +import org.springframework.ai.neo4j.vectorstore.filter.Neo4jVectorFilterExpressionConverter; import org.springframework.ai.vectorstore.observation.AbstractObservationVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * A vector store implementation that stores and retrieves vectors in a Neo4j database. @@ -73,36 +76,77 @@ public class Neo4jVectorStore extends AbstractObservationVectorStore implements Neo4jDistanceType.COSINE, VectorStoreSimilarityMetric.COSINE, Neo4jDistanceType.EUCLIDEAN, VectorStoreSimilarityMetric.EUCLIDEAN); - private final Neo4jVectorFilterExpressionConverter filterExpressionConverter = new Neo4jVectorFilterExpressionConverter(); - private final Driver driver; - private final EmbeddingModel embeddingModel; + private final SessionConfig sessionConfig; + + private final int embeddingDimension; + + private final Neo4jDistanceType distanceType; + + private final String embeddingProperty; + + private final String label; - private final Neo4jVectorStoreConfig config; + private final String indexName; + + private final String indexNameNotSanitized; + + private final String idProperty; + + private final String constraintName; + + private final Neo4jVectorFilterExpressionConverter filterExpressionConverter = new Neo4jVectorFilterExpressionConverter(); private final boolean initializeSchema; private final BatchingStrategy batchingStrategy; + @Deprecated(since = "1.0.0-M5", forRemoval = true) public Neo4jVectorStore(Driver driver, EmbeddingModel embeddingModel, Neo4jVectorStoreConfig config, boolean initializeSchema) { this(driver, embeddingModel, config, initializeSchema, ObservationRegistry.NOOP, null, new TokenCountBatchingStrategy()); } + @Deprecated(since = "1.0.0-M5", forRemoval = true) public Neo4jVectorStore(Driver driver, EmbeddingModel embeddingModel, Neo4jVectorStoreConfig config, boolean initializeSchema, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - super(observationRegistry, customObservationConvention); - - this.initializeSchema = initializeSchema; - Assert.notNull(driver, "Neo4j driver must not be null"); - Assert.notNull(embeddingModel, "Embedding model must not be null"); - this.driver = driver; - this.embeddingModel = embeddingModel; - this.config = config; - this.batchingStrategy = batchingStrategy; + + this(builder().driver(driver) + .embeddingModel(embeddingModel) + .sessionConfig(config.sessionConfig) + .embeddingDimension(config.embeddingDimension) + .distanceType(config.distanceType) + .embeddingProperty(config.embeddingProperty) + .label(config.label) + .indexName(config.indexName) + .idProperty(config.idProperty) + .constraintName(config.constraintName) + .initializeSchema(initializeSchema) + .observationRegistry(observationRegistry) + .customObservationConvention(customObservationConvention) + .batchingStrategy(batchingStrategy)); + } + + protected Neo4jVectorStore(Neo4jBuilder builder) { + super(builder); + + Assert.notNull(builder.driver, "Neo4j driver must not be null"); + + this.driver = builder.driver; + this.sessionConfig = builder.sessionConfig; + this.embeddingDimension = builder.embeddingDimension; + this.distanceType = builder.distanceType; + this.embeddingProperty = SchemaNames.sanitize(builder.embeddingProperty).orElseThrow(); + this.label = SchemaNames.sanitize(builder.label).orElseThrow(); + this.indexNameNotSanitized = builder.indexName; + this.indexName = SchemaNames.sanitize(builder.indexName, true).orElseThrow(); + this.idProperty = SchemaNames.sanitize(builder.idProperty).orElseThrow(); + this.constraintName = SchemaNames.sanitize(builder.constraintName).orElseThrow(); + this.initializeSchema = builder.initializeSchema; + this.batchingStrategy = builder.batchingStrategy; } @Override @@ -127,17 +171,17 @@ public void doAdd(List documents) { u += row.properties WITH row, u CALL db.create.setNodeVectorProperty(u, $embeddingProperty, row[$embeddingProperty]) - """.formatted(this.config.label, this.config.idProperty); - session.executeWrite( - tx -> tx.run(statement, Map.of("rows", rows, "embeddingProperty", this.config.embeddingProperty)) - .consume()); + """.formatted(this.label, this.idProperty); + session + .executeWrite(tx -> tx.run(statement, Map.of("rows", rows, "embeddingProperty", this.embeddingProperty)) + .consume()); } } @Override public Optional doDelete(List idList) { - try (var session = this.driver.session(this.config.sessionConfig)) { + try (var session = this.driver.session(this.sessionConfig)) { // Those queries with internal, cypher based transaction management cannot be // run with executeWrite @@ -145,7 +189,7 @@ public Optional doDelete(List idList) { .run(""" MATCH (n:%s) WHERE n.%s IN $ids CALL { WITH n DETACH DELETE n } IN TRANSACTIONS OF $transactionSize ROWS - """.formatted(this.config.label, this.config.idProperty), + """.formatted(this.label, this.idProperty), Map.of("ids", idList, "transactionSize", DEFAULT_TRANSACTION_SIZE)) .consume(); return Optional.of(idList.size() == summary.counters().nodesDeleted()); @@ -159,7 +203,7 @@ public List doSimilaritySearch(SearchRequest request) { "The similarity score is bounded between 0 and 1; least to most similar respectively."); var embedding = Values.value(this.embeddingModel.embed(request.getQuery())); - try (var session = this.driver.session(this.config.sessionConfig)) { + try (var session = this.driver.session(this.sessionConfig)) { StringBuilder condition = new StringBuilder("score >= $threshold"); if (request.hasFilterExpression()) { condition.append(" AND ") @@ -172,8 +216,9 @@ public List doSimilaritySearch(SearchRequest request) { RETURN node, score""".formatted(condition); return session.executeRead(tx -> tx - .run(query, Map.of("indexName", this.config.indexNameNotSanitized, "numberOfNearestNeighbours", - request.getTopK(), "embeddingValue", embedding, "threshold", request.getSimilarityThreshold())) + .run(query, + Map.of("indexName", this.indexNameNotSanitized, "numberOfNearestNeighbours", request.getTopK(), + "embeddingValue", embedding, "threshold", request.getSimilarityThreshold())) .list(this::recordToDocument)); } } @@ -185,11 +230,11 @@ public void afterPropertiesSet() { return; } - try (var session = this.driver.session(this.config.sessionConfig)) { + try (var session = this.driver.session(this.sessionConfig)) { session.executeWriteWithoutResult(tx -> { tx.run("CREATE CONSTRAINT %s IF NOT EXISTS FOR (n:%s) REQUIRE n.%s IS UNIQUE" - .formatted(this.config.constraintName, this.config.label, this.config.idProperty)).consume(); + .formatted(this.constraintName, this.label, this.idProperty)).consume(); var statement = """ CREATE VECTOR INDEX %s IF NOT EXISTS FOR (n:%s) ON (n.%s) @@ -197,8 +242,8 @@ public void afterPropertiesSet() { `vector.dimensions`: %d, `vector.similarity_function`: '%s' }} - """.formatted(this.config.indexName, this.config.label, this.config.embeddingProperty, - this.config.embeddingDimension, this.config.distanceType.name); + """.formatted(this.indexName, this.label, this.embeddingProperty, this.embeddingDimension, + this.distanceType.name); tx.run(statement).consume(); }); @@ -219,7 +264,7 @@ private Map documentToRecord(Document document, float[] embeddin document.getMetadata().forEach((k, v) -> properties.put("metadata." + k, Values.value(v))); row.put("properties", properties); - row.put(this.config.embeddingProperty, Values.value(embedding)); + row.put(this.embeddingProperty, Values.value(embedding)); return row; } @@ -235,7 +280,7 @@ private Document recordToDocument(org.neo4j.driver.Record neoRecord) { }); return Document.builder() - .id(node.get(this.config.idProperty).asString()) + .id(node.get(this.idProperty).asString()) .text(node.get("text").asString()) .metadata(Map.copyOf(metaData)) .score((double) score) @@ -246,16 +291,16 @@ private Document recordToDocument(org.neo4j.driver.Record neoRecord) { public VectorStoreObservationContext.Builder createObservationContextBuilder(String operationName) { return VectorStoreObservationContext.builder(VectorStoreProvider.NEO4J.value(), operationName) - .withCollectionName(this.config.indexName) + .withCollectionName(this.indexName) .withDimensions(this.embeddingModel.dimensions()) .withSimilarityMetric(getSimilarityMetric()); } private String getSimilarityMetric() { - if (!SIMILARITY_TYPE_MAPPING.containsKey(this.config.distanceType)) { - return this.config.distanceType.name(); + if (!SIMILARITY_TYPE_MAPPING.containsKey(this.distanceType)) { + return this.distanceType.name(); } - return SIMILARITY_TYPE_MAPPING.get(this.config.distanceType).value(); + return SIMILARITY_TYPE_MAPPING.get(this.distanceType).value(); } /** @@ -273,9 +318,181 @@ public enum Neo4jDistanceType { } + public static Neo4jBuilder builder() { + return new Neo4jBuilder(); + } + + public static class Neo4jBuilder extends AbstractVectorStoreBuilder { + + private Driver driver; + + private SessionConfig sessionConfig = SessionConfig.defaultConfig(); + + private int embeddingDimension = DEFAULT_EMBEDDING_DIMENSION; + + private Neo4jDistanceType distanceType = Neo4jDistanceType.COSINE; + + private String label = DEFAULT_LABEL; + + private String embeddingProperty = DEFAULT_EMBEDDING_PROPERTY; + + private String indexName = DEFAULT_INDEX_NAME; + + private String idProperty = DEFAULT_ID_PROPERTY; + + private String constraintName = DEFAULT_CONSTRAINT_NAME; + + private boolean initializeSchema = false; + + private BatchingStrategy batchingStrategy = new TokenCountBatchingStrategy(); + + public Neo4jBuilder driver(Driver driver) { + Assert.notNull(driver, "Neo4j driver must not be null"); + this.driver = driver; + return this; + } + + /** + * Sets the database name. When provided and not blank, creates a session config + * for that database. + * @param databaseName the database name to use + * @return the builder instance + */ + public Neo4jBuilder databaseName(String databaseName) { + if (StringUtils.hasText(databaseName)) { + this.sessionConfig = SessionConfig.forDatabase(databaseName); + } + return this; + } + + /** + * Sets the session configuration directly. + * @param sessionConfig the session configuration to use + * @return the builder instance + */ + public Neo4jBuilder sessionConfig(SessionConfig sessionConfig) { + this.sessionConfig = sessionConfig; + return this; + } + + /** + * Sets the embedding dimension. Must be positive. + * @param dimension the dimension of the embedding + * @return the builder instance + * @throws IllegalArgumentException if dimension is less than 1 + */ + public Neo4jBuilder embeddingDimension(int dimension) { + Assert.isTrue(dimension >= 1, "Dimension has to be positive"); + this.embeddingDimension = dimension; + return this; + } + + /** + * Sets the distance type for index storage and queries. + * @param distanceType the distance type to use + * @return the builder instance + * @throws IllegalArgumentException if distanceType is null + */ + public Neo4jBuilder distanceType(Neo4jDistanceType distanceType) { + Assert.notNull(distanceType, "Distance type may not be null"); + this.distanceType = distanceType; + return this; + } + + /** + * Sets the label for document nodes. + * @param label the label to use + * @return the builder instance + */ + public Neo4jBuilder label(String label) { + if (StringUtils.hasText(label)) { + this.label = label; + } + return this; + } + + /** + * Sets the property name for storing embeddings. + * @param embeddingProperty the property name to use + * @return the builder instance + */ + public Neo4jBuilder embeddingProperty(String embeddingProperty) { + if (StringUtils.hasText(embeddingProperty)) { + this.embeddingProperty = embeddingProperty; + } + return this; + } + + /** + * Sets the name of the vector index. + * @param indexName the index name to use + * @return the builder instance + */ + public Neo4jBuilder indexName(String indexName) { + if (StringUtils.hasText(indexName)) { + this.indexName = indexName; + } + return this; + } + + /** + * Sets the property name for document IDs. + * @param idProperty the property name to use + * @return the builder instance + */ + public Neo4jBuilder idProperty(String idProperty) { + if (StringUtils.hasText(idProperty)) { + this.idProperty = idProperty; + } + return this; + } + + /** + * Sets the name of the unique constraint. + * @param constraintName the constraint name to use + * @return the builder instance + */ + public Neo4jBuilder constraintName(String constraintName) { + if (StringUtils.hasText(constraintName)) { + this.constraintName = constraintName; + } + return this; + } + + /** + * Sets whether to initialize the schema. + * @param initializeSchema true to initialize schema, false otherwise + * @return the builder instance + */ + public Neo4jBuilder initializeSchema(boolean initializeSchema) { + this.initializeSchema = initializeSchema; + return this; + } + + /** + * Sets the batching strategy. + * @param batchingStrategy the strategy to use + * @return the builder instance + * @throws IllegalArgumentException if batchingStrategy is null + */ + public Neo4jBuilder batchingStrategy(BatchingStrategy batchingStrategy) { + Assert.notNull(batchingStrategy, "BatchingStrategy must not be null"); + this.batchingStrategy = batchingStrategy; + return this; + } + + @Override + public Neo4jVectorStore build() { + validate(); + return new Neo4jVectorStore(this); + } + + } + /** * Configuration for the Neo4j vector store. */ + @Deprecated(since = "1.0.0-M5", forRemoval = true) public static final class Neo4jVectorStoreConfig { private final SessionConfig sessionConfig; @@ -317,19 +534,20 @@ private Neo4jVectorStoreConfig(Builder builder) { * Start building a new configuration. * @return The entry point for creating a new configuration. */ + @Deprecated(since = "1.0.0-M5", forRemoval = true) public static Builder builder() { - return new Builder(); } /** * {@return the default config} */ + @Deprecated(since = "1.0.0-M5", forRemoval = true) public static Neo4jVectorStoreConfig defaultConfig() { - return builder().build(); } + @Deprecated(since = "1.0.0-M5", forRemoval = true) public static final class Builder { private String databaseName; diff --git a/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/filter/Neo4jVectorFilterExpressionConverter.java b/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/neo4j/vectorstore/filter/Neo4jVectorFilterExpressionConverter.java similarity index 96% rename from vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/filter/Neo4jVectorFilterExpressionConverter.java rename to vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/neo4j/vectorstore/filter/Neo4jVectorFilterExpressionConverter.java index 747c0807a5a..2b1a667d195 100644 --- a/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/filter/Neo4jVectorFilterExpressionConverter.java +++ b/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/neo4j/vectorstore/filter/Neo4jVectorFilterExpressionConverter.java @@ -14,8 +14,9 @@ * limitations under the License. */ -package org.springframework.ai.vectorstore.filter; +package org.springframework.ai.neo4j.vectorstore.filter; +import org.springframework.ai.vectorstore.filter.Filter; import org.springframework.ai.vectorstore.filter.Filter.Expression; import org.springframework.ai.vectorstore.filter.Filter.Group; import org.springframework.ai.vectorstore.filter.Filter.Key; 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/neo4j/vectorstore/Neo4jImage.java similarity index 94% rename from vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jImage.java rename to vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/neo4j/vectorstore/Neo4jImage.java index e0133dbf1fe..c2ec7cde340 100644 --- 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/neo4j/vectorstore/Neo4jImage.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.vectorstore; +package org.springframework.ai.neo4j.vectorstore; import org.testcontainers.utility.DockerImageName; diff --git a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jVectorStoreIT.java b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/neo4j/vectorstore/Neo4jVectorStoreIT.java similarity index 97% rename from vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jVectorStoreIT.java rename to vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/neo4j/vectorstore/Neo4jVectorStoreIT.java index b5bc62ef9f5..2bab7334a29 100644 --- a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jVectorStoreIT.java +++ b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/neo4j/vectorstore/Neo4jVectorStoreIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.vectorstore; +package org.springframework.ai.neo4j.vectorstore; import java.util.Collections; import java.util.List; @@ -37,6 +37,8 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.openai.OpenAiEmbeddingModel; import org.springframework.ai.openai.api.OpenAiApi; +import org.springframework.ai.vectorstore.SearchRequest; +import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.filter.FilterExpressionTextParser; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -289,8 +291,11 @@ public static class TestApplication { @Bean public VectorStore vectorStore(Driver driver, EmbeddingModel embeddingModel) { - return new Neo4jVectorStore(driver, embeddingModel, Neo4jVectorStore.Neo4jVectorStoreConfig.defaultConfig(), - true); + return Neo4jVectorStore.builder() + .driver(driver) + .embeddingModel(embeddingModel) + .initializeSchema(true) + .build(); } @Bean 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/neo4j/vectorstore/Neo4jVectorStoreObservationIT.java similarity index 94% rename from vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/Neo4jVectorStoreObservationIT.java rename to vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/neo4j/vectorstore/Neo4jVectorStoreObservationIT.java index 1c841b1c1da..d0bea21dcb0 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/neo4j/vectorstore/Neo4jVectorStoreObservationIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.vectorstore; +package org.springframework.ai.neo4j.vectorstore; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -43,6 +43,8 @@ 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.SearchRequest; +import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention; import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.HighCardinalityKeyNames; import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.LowCardinalityKeyNames; @@ -176,8 +178,14 @@ public TestObservationRegistry observationRegistry() { public VectorStore vectorStore(Driver driver, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return new Neo4jVectorStore(driver, embeddingModel, Neo4jVectorStore.Neo4jVectorStoreConfig.defaultConfig(), - true, observationRegistry, null, new TokenCountBatchingStrategy()); + return Neo4jVectorStore.builder() + .driver(driver) + .embeddingModel(embeddingModel) + .initializeSchema(true) + .observationRegistry(observationRegistry) + .customObservationConvention(null) + .batchingStrategy(new TokenCountBatchingStrategy()) + .build(); } @Bean diff --git a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/filter/Neo4jVectorFilterExpressionConverterTests.java b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/neo4j/vectorstore/filter/Neo4jVectorFilterExpressionConverterTests.java similarity index 95% rename from vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/filter/Neo4jVectorFilterExpressionConverterTests.java rename to vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/neo4j/vectorstore/filter/Neo4jVectorFilterExpressionConverterTests.java index 4eeaa22f198..d0fcf988756 100644 --- a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/filter/Neo4jVectorFilterExpressionConverterTests.java +++ b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/neo4j/vectorstore/filter/Neo4jVectorFilterExpressionConverterTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.vectorstore.filter; +package org.springframework.ai.neo4j.vectorstore.filter; import java.util.List; @@ -24,6 +24,8 @@ import org.springframework.ai.vectorstore.filter.Filter.Group; import org.springframework.ai.vectorstore.filter.Filter.Key; import org.springframework.ai.vectorstore.filter.Filter.Value; +import org.springframework.ai.vectorstore.filter.FilterExpressionConverter; +import org.springframework.ai.vectorstore.filter.FilterExpressionTextParser; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ai.vectorstore.filter.Filter.ExpressionType.AND; @@ -130,7 +132,7 @@ public void testComplexIdentifiers() { @Test public void testComplexIdentifiers2() { - Filter.Expression expr = new FilterExpressionTextParser() + Expression expr = new FilterExpressionTextParser() .parse("author in ['john', 'jill'] && 'article_type' == 'blog'"); String vectorExpr = this.converter.convertExpression(expr); assertThat(vectorExpr)