Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: spring-projects/spring-data-examples
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9b64cc2
Choose a base ref
...
head repository: spring-projects/spring-data-examples
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f4e1c65
Choose a head ref
  • 4 commits
  • 33 files changed
  • 1 contributor

Commits on May 19, 2025

  1. Verified

    This commit was signed with the committer’s verified signature.
    christophstrobl Christoph Strobl
    Copy the full SHA
    0490556 View commit details

Commits on May 20, 2025

  1. Verified

    This commit was signed with the committer’s verified signature.
    christophstrobl Christoph Strobl
    Copy the full SHA
    5a4252f View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    christophstrobl Christoph Strobl
    Copy the full SHA
    cb3c077 View commit details
  3. Rename tests.

    christophstrobl committed May 20, 2025

    Verified

    This commit was signed with the committer’s verified signature.
    christophstrobl Christoph Strobl
    Copy the full SHA
    f4e1c65 View commit details
Showing with 1,234 additions and 1 deletion.
  1. +3 −0 README.adoc
  2. +1 −0 cassandra/pom.xml
  3. +2 −1 cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraExtension.java
  4. +37 −0 cassandra/vector-search/README.md
  5. +85 −0 cassandra/vector-search/pom.xml
  6. +76 −0 cassandra/vector-search/src/main/java/example/springdata/vector/Comment.java
  7. +32 −0 cassandra/vector-search/src/main/java/example/springdata/vector/CommentRepository.java
  8. +52 −0 cassandra/vector-search/src/main/java/example/springdata/vector/VectorApp.java
  9. +6 −0 cassandra/vector-search/src/main/resources/application.properties
  10. +43 −0 cassandra/vector-search/src/test/java/example/springdata/vector/CassandraDBConfiguration.java
  11. +64 −0 cassandra/vector-search/src/test/java/example/springdata/vector/CassandraVectorSearchTest.java
  12. +1 −0 jpa/pom.xml
  13. +36 −0 jpa/vector-search/README.md
  14. +120 −0 jpa/vector-search/pom.xml
  15. +76 −0 jpa/vector-search/src/main/java/example/springdata/vector/Comment.java
  16. +34 −0 jpa/vector-search/src/main/java/example/springdata/vector/CommentRepository.java
  17. +50 −0 jpa/vector-search/src/main/java/example/springdata/vector/VectorApp.java
  18. +4 −0 jpa/vector-search/src/main/resources/application.properties
  19. +11 −0 jpa/vector-search/src/main/resources/pgvector.sql
  20. +54 −0 jpa/vector-search/src/test/java/example/springdata/vector/JpaVectorSearchTest.java
  21. +35 −0 jpa/vector-search/src/test/java/example/springdata/vector/PGVectorConfiguration.java
  22. +1 −0 mongodb/pom.xml
  23. +4 −0 mongodb/util/pom.xml
  24. +49 −0 ...db/util/src/main/java/example/springdata/mongodb/util/AtlasContainerConnectionDetailsFactory.java
  25. +3 −0 mongodb/util/src/main/resources/META-INF/spring.factories
  26. +36 −0 mongodb/vector-search/README.md
  27. +71 −0 mongodb/vector-search/pom.xml
  28. +69 −0 mongodb/vector-search/src/main/java/example/springdata/vector/Comment.java
  29. +34 −0 mongodb/vector-search/src/main/java/example/springdata/vector/CommentRepository.java
  30. +51 −0 mongodb/vector-search/src/main/java/example/springdata/vector/VectorApp.java
  31. +1 −0 mongodb/vector-search/src/main/resources/application.properties
  32. +32 −0 mongodb/vector-search/src/test/java/example/springdata/vector/MongoDBConfiguration.java
  33. +61 −0 mongodb/vector-search/src/test/java/example/springdata/vector/MongoDBVectorSearchTest.java
3 changes: 3 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ We have separate folders for the samples of individual modules:
* `example` - Shows core Spring Data support for Apache Cassandra.
* `kotlin` - Example for using Cassandra with Kotlin.
* `reactive` - Example project to show reactive template and repository support.
* `vector-search` - Example how to do vector search with a Spring Data Cassandra repository.

== Spring Data Elasticsearch

@@ -46,6 +47,7 @@ Contains also examples running on Virtual Threads.
* `security` - Example of how to integrate Spring Data JPA Repositories with Spring Security.
* `showcase` - Refactoring show case of how to improve a plain-JPA-based persistence layer by using Spring Data JPA (read: removing close to all of the implementation code).Follow the `demo.txt` file for detailed instructions.
* `vavr` - Shows the support of https://www.vavr.io[Vavr] collection types as return types for query methods.
* `vector-search` - Example how to do vector search with a Spring Data JPA repository and `hibernate-vector`.

== Spring Data LDAP

@@ -68,6 +70,7 @@ Contains also examples running on Virtual Threads.
* `security` - Example project showing usage of Spring Security with MongoDB.
* `text-search` - Example project showing usage of MongoDB text search feature.
* `transactions` - Example project for imperative and reactive MongoDB 4.0 transaction support.
* `vector-search` - Example how to do vector search with a Spring Data MongoDB repository.

== Spring Data Neo4j

1 change: 1 addition & 0 deletions cassandra/pom.xml
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
<module>example</module>
<module>kotlin</module>
<module>reactive</module>
<module>vector-search</module>
</modules>

<dependencies>
Original file line number Diff line number Diff line change
@@ -54,6 +54,7 @@ public void beforeAll(ExtensionContext context) {
CassandraContainer container = runTestcontainer();
System.setProperty("spring.cassandra.port", "" + container.getMappedPort(9042));
System.setProperty("spring.cassandra.contact-points", "" + container.getHost());
System.setProperty("spring.cassandra.local-datacenter", container.getLocalDatacenter());

return new CassandraServer(container.getHost(), container.getMappedPort(9042),
CassandraServer.RuntimeMode.EMBEDDED_IF_NOT_RUNNING);
@@ -109,6 +110,6 @@ private CassandraContainer<?> runTestcontainer() {
private String getCassandraDockerImageName() {

return String.format("cassandra:%s",
Optional.ofNullable(System.getenv("CASSANDRA_VERSION")).filter(StringUtils::hasText).orElse("3.11.10"));
Optional.ofNullable(System.getenv("CASSANDRA_VERSION")).filter(StringUtils::hasText).orElse("5.0.4"));
}
}
37 changes: 37 additions & 0 deletions cassandra/vector-search/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Spring Data for Apache Cassandra - Vector Search Example

This project
contains [Vector Search](https://docs.spring.io/spring-data/cassandra/reference/5.0/cassandra/repositories/vector-search.html)
with Spring Data for Apache Cassandra.

## Vector Support

The Spring Data `Vector` type can be used in repository query methods.
Domain type properties of managed domain types are required to use a numeric array representation for embeddings.

```java

@Table
public class Comment {

@Id
private String id;

private String country;
private String description;

@SaiIndexed
@VectorType(dimensions = 5)
private Vector embedding;

// ...
}


public interface CommentRepository extends Repository<Comment, String> {

SearchResults<Comment> searchTop10ByEmbeddingNear(Vector embedding, ScoringFunction function);
}
```

This example contains a test class to illustrate vector search with a Repository in `CassandraVectorSearchTest`.
85 changes: 85 additions & 0 deletions cassandra/vector-search/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data.examples</groupId>
<artifactId>spring-data-cassandra-examples</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>

<groupId>org.example</groupId>
<artifactId>spring-data-cassandra-vector-search</artifactId>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>7.0.0-M5</spring.version>
<spring-data-bom.version>2025.1.0-M3</spring-data-bom.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<version>5.0.0-M3</version>
</dependency>

<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<version>1.0.0</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>cassandra</artifactId>
<exclusions>
<exclusion>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.data.examples</groupId>
<artifactId>spring-data-cassandra-example-utils</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2025 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 example.springdata.vector;

import java.util.UUID;

import org.springframework.data.annotation.Id;
import org.springframework.data.cassandra.core.mapping.SaiIndexed;
import org.springframework.data.cassandra.core.mapping.Table;
import org.springframework.data.cassandra.core.mapping.VectorType;
import org.springframework.data.domain.Vector;

/**
* Sample entity containing a {@link Vector vector} {@link #embedding}.
*/
@Table
public class Comment {

@Id
private String id;

private String country;
private String description;

@SaiIndexed
@VectorType(dimensions = 5)
private Vector embedding;

public Comment() {
}

public Comment(String country, String description, Vector embedding) {
this.id = UUID.randomUUID().toString();
this.country = country;
this.description = description;
this.embedding = embedding;
}

public static Comment of(Comment source) {
return new Comment(source.getCountry(), source.getDescription(), source.getEmbedding());
}

public String getId() {
return id;
}

public String getCountry() {
return country;
}

public String getDescription() {
return description;
}

public Vector getEmbedding() {
return embedding;
}

@Override
public String toString() {
return "%s (%s)".formatted(getDescription(), getCountry());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2025 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 example.springdata.vector;

import org.springframework.data.cassandra.repository.Query;
import org.springframework.data.domain.Limit;
import org.springframework.data.domain.Score;
import org.springframework.data.domain.ScoringFunction;
import org.springframework.data.domain.SearchResults;
import org.springframework.data.domain.Vector;
import org.springframework.data.repository.CrudRepository;

public interface CommentRepository extends CrudRepository<Comment, String> {

SearchResults<Comment> searchTop10ByEmbeddingNear(Vector embedding, ScoringFunction function);

@Query("SELECT id, description, country, similarity_cosine(embedding,:embedding) AS score FROM comment ORDER BY embedding ANN OF :embedding LIMIT :limit")
SearchResults<Comment> searchAnnotated(Vector embedding, Score distance, Limit limit);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2025 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 example.springdata.vector;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.domain.Vector;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class VectorApp {

public static void main(String[] args) {
SpringApplication.run(VectorApp.class, args);
}

@Component
static class DbInitializer implements CommandLineRunner {

private final CassandraTemplate template;

DbInitializer(CassandraTemplate template) {
this.template = template;
}

@Override
public void run(String... args) {

template.truncate(Comment.class);

template.insert(new Comment("de", "comment 'one'", Vector.of(0.1001f, 0.22345f, 0.33456f, 0.44567f, 0.55678f)));
template.insert(new Comment("de", "comment 'two'", Vector.of(0.2001f, 0.32345f, 0.43456f, 0.54567f, 0.65678f)));
template.insert(new Comment("en", "comment 'three'", Vector.of(0.9001f, 0.82345f, 0.73456f, 0.64567f, 0.55678f)));
template.insert(new Comment("de", "comment 'four'", Vector.of(0.9001f, 0.92345f, 0.93456f, 0.94567f, 0.95678f)));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
logging.level.org=WARN
logging.level.com.datastax=WARN

spring.cassandra.schema-action=recreate
spring.cassandra.
spring.cassandra.keyspace-name=vector_search_keyspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2025 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 example.springdata.vector;

import java.net.InetSocketAddress;

import com.datastax.oss.driver.api.core.CqlSession;
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;
import org.springframework.boot.autoconfigure.cassandra.CqlSessionBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CassandraDBConfiguration {

@Bean
CqlSessionBuilderCustomizer sessionBuilderCustomizer(CassandraProperties properties) {
return sessionBuilder -> {

InetSocketAddress contactPoint = new InetSocketAddress(properties.getContactPoints().iterator().next(), properties.getPort());

CqlSession session = CqlSession.builder().addContactPoint(contactPoint)
.withLocalDatacenter(properties.getLocalDatacenter()).build();

session.execute("CREATE KEYSPACE IF NOT EXISTS " + properties.getKeyspaceName() + " WITH replication = \n"
+ "{'class':'SimpleStrategy','replication_factor':'1'};");
session.close();
};
}
}
Loading