Skip to content

Commit bb1f113

Browse files
christophstroblmp911de
authored andcommitted
Add MongoDB vector search example.
Using Atlas local. See #707
1 parent a8f8407 commit bb1f113

File tree

11 files changed

+330
-0
lines changed

11 files changed

+330
-0
lines changed

README.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Contains also examples running on Virtual Threads.
6969
* `security` - Example project showing usage of Spring Security with MongoDB.
7070
* `text-search` - Example project showing usage of MongoDB text search feature.
7171
* `transactions` - Example project for imperative and reactive MongoDB 4.0 transaction support.
72+
* `vector-search` - Example how to do vector search with a Spring Data MongoDB repository.
7273

7374
== Spring Data Neo4j
7475

mongodb/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<module>linking</module>
3838
<module>util</module>
3939
<module>fragment-spi</module>
40+
<module>vector-search</module>
4041
</modules>
4142

4243
<dependencyManagement>

mongodb/util/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
<groupId>org.testcontainers</groupId>
2929
<artifactId>testcontainers-mongodb</artifactId>
3030
</dependency>
31+
<dependency>
32+
<groupId>org.springframework.boot</groupId>
33+
<artifactId>spring-boot-testcontainers</artifactId>
34+
</dependency>
3135

3236
</dependencies>
3337

mongodb/vector-search/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Spring Data MongoDB - Vector Search Example
2+
3+
This project
4+
contains [Vector Search](https://docs.spring.io/spring-data/mongodb/reference/5.0/mongodb/repositories/vector-search.html)
5+
with Spring Data MongoDB.
6+
7+
## Vector Support
8+
9+
The Spring Data `Vector` type can be used in repository query methods.
10+
Domain type properties of managed domain types are required to use a numeric array representation for embeddings.
11+
12+
```java
13+
14+
@Document
15+
public class Comment {
16+
17+
@Id
18+
private ObjectId id;
19+
20+
private String country;
21+
private String description;
22+
23+
private Vector embedding;
24+
25+
// ...
26+
}
27+
28+
29+
public interface CommentRepository extends Repository<Comment, String> {
30+
31+
@VectorSearch(indexName = "cosine-index", searchType = VectorSearchOperation.SearchType.ANN)
32+
SearchResults<Comment> searchTop10ByCountryAndEmbeddingNear(String country, Vector vector, Score distance);
33+
}
34+
```
35+
36+
This example contains a test class to illustrate vector search with a Repository
37+
in `VectorAppTest`.

mongodb/vector-search/pom.xml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>org.springframework.data.examples</groupId>
9+
<artifactId>spring-data-mongodb-examples</artifactId>
10+
<version>4.0.0-SNAPSHOT</version>
11+
</parent>
12+
13+
<artifactId>spring-data-mongodb-vector-search</artifactId>
14+
15+
<dependencies>
16+
17+
<dependency>
18+
<groupId>org.springframework.data.examples</groupId>
19+
<artifactId>spring-data-mongodb-example-utils</artifactId>
20+
<scope>test</scope>
21+
</dependency>
22+
23+
</dependencies>
24+
25+
<build>
26+
<plugins>
27+
<plugin>
28+
<groupId>org.apache.maven.plugins</groupId>
29+
<artifactId>maven-compiler-plugin</artifactId>
30+
</plugin>
31+
<plugin>
32+
<groupId>org.springframework.boot</groupId>
33+
<artifactId>spring-boot-maven-plugin</artifactId>
34+
</plugin>
35+
</plugins>
36+
</build>
37+
38+
</project>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package example.springdata.vector;
17+
18+
import org.bson.types.ObjectId;
19+
import org.springframework.data.domain.Vector;
20+
import org.springframework.data.mongodb.core.mapping.Document;
21+
22+
/**
23+
* Sample entity containing a {@link Vector vector} {@link #embedding}.
24+
*/
25+
@Document
26+
public class Comment {
27+
28+
private ObjectId id;
29+
30+
private String country;
31+
private String description;
32+
33+
private Vector embedding;
34+
35+
public Comment() {
36+
}
37+
38+
public Comment(String country, String description, Vector embedding) {
39+
this.country = country;
40+
this.description = description;
41+
this.embedding = embedding;
42+
}
43+
44+
public static Comment of(Comment source) {
45+
return new Comment(source.getCountry(), source.getDescription(), source.getEmbedding());
46+
}
47+
48+
public ObjectId getId() {
49+
return id;
50+
}
51+
52+
public String getCountry() {
53+
return country;
54+
}
55+
56+
public String getDescription() {
57+
return description;
58+
}
59+
60+
public Vector getEmbedding() {
61+
return embedding;
62+
}
63+
64+
65+
@Override
66+
public String toString() {
67+
return "%s (%s)".formatted(getDescription(), getCountry());
68+
}
69+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package example.springdata.vector;
17+
18+
import org.springframework.data.domain.Limit;
19+
import org.springframework.data.domain.Score;
20+
import org.springframework.data.domain.SearchResults;
21+
import org.springframework.data.domain.Vector;
22+
import org.springframework.data.mongodb.core.aggregation.VectorSearchOperation;
23+
import org.springframework.data.mongodb.repository.VectorSearch;
24+
import org.springframework.data.repository.CrudRepository;
25+
26+
public interface CommentRepository extends CrudRepository<Comment, String> {
27+
28+
@VectorSearch(indexName = "cosine-index", searchType = VectorSearchOperation.SearchType.ANN)
29+
SearchResults<Comment> searchTop10ByCountryAndEmbeddingNear(String country, Vector vector, Score distance);
30+
31+
@VectorSearch(indexName = "cosine-index", filter = "{country: ?0}", numCandidates = "#{#limit.max*10}",
32+
searchType = VectorSearchOperation.SearchType.ANN)
33+
SearchResults<Comment> searchAnnotated(String country, Vector vector, Score distance, Limit limit);
34+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package example.springdata.vector;
17+
18+
import org.springframework.boot.CommandLineRunner;
19+
import org.springframework.boot.SpringApplication;
20+
import org.springframework.boot.autoconfigure.SpringBootApplication;
21+
import org.springframework.data.domain.Vector;
22+
import org.springframework.stereotype.Component;
23+
24+
@SpringBootApplication
25+
public class VectorApp {
26+
27+
public static void main(String[] args) {
28+
SpringApplication.run(VectorApp.class, args);
29+
}
30+
31+
@Component
32+
static class DbInitializer implements CommandLineRunner {
33+
34+
private final CommentRepository repository;
35+
36+
DbInitializer(CommentRepository repository) {
37+
this.repository = repository;
38+
}
39+
40+
@Override
41+
public void run(String... args) {
42+
43+
repository.deleteAll();
44+
45+
repository.save(new Comment("de", "comment 'one'", Vector.of(0.1001f, 0.22345f, 0.33456f, 0.44567f, 0.55678f)));
46+
repository.save(new Comment("de", "comment 'two'", Vector.of(0.2001f, 0.32345f, 0.43456f, 0.54567f, 0.65678f)));
47+
repository.save(new Comment("en", "comment 'three'", Vector.of(0.9001f, 0.82345f, 0.73456f, 0.64567f, 0.55678f)));
48+
repository.save(new Comment("de", "comment 'four'", Vector.of(0.9001f, 0.92345f, 0.93456f, 0.94567f, 0.95678f)));
49+
}
50+
}
51+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
logging.level.org=WARN
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package example.springdata.vector;
17+
18+
import example.springdata.mongodb.util.MongoContainers;
19+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
20+
import org.springframework.context.annotation.Bean;
21+
import org.springframework.context.annotation.Configuration;
22+
23+
import org.testcontainers.mongodb.MongoDBAtlasLocalContainer;
24+
25+
@Configuration
26+
public class MongoDBConfiguration {
27+
28+
@Bean
29+
@ServiceConnection(name = "mongo")
30+
MongoDBAtlasLocalContainer atlasContainer() {
31+
return MongoContainers.getAtlasContainer();
32+
}
33+
}

0 commit comments

Comments
 (0)