diff --git a/spring-ai-2/docker-compose.yml b/spring-ai-2/docker-compose.yml
new file mode 100644
index 000000000000..2b4b28761035
--- /dev/null
+++ b/spring-ai-2/docker-compose.yml
@@ -0,0 +1,29 @@
+services:
+ postgres:
+ image: pgvector/pgvector:pg17
+ environment:
+ POSTGRES_DB: vectordb
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ ports:
+ - "5434:5432"
+ healthcheck:
+ test: [ "CMD-SHELL", "pg_isready -U postgres" ]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ ollama:
+ image: ollama/ollama:latest
+ ports:
+ - "11435:11434"
+ volumes:
+ - ollama_data:/root/.ollama
+ healthcheck:
+ test: [ "CMD", "curl", "-f", "http://localhost:11435/api/health" ]
+ interval: 10s
+ timeout: 5s
+ retries: 10
+
+volumes:
+ ollama_data:
\ No newline at end of file
diff --git a/spring-ai-2/pom.xml b/spring-ai-2/pom.xml
index a690d50d6c3b..ecdc410ed53c 100644
--- a/spring-ai-2/pom.xml
+++ b/spring-ai-2/pom.xml
@@ -72,6 +72,10 @@
hsqldb
runtime
+
+ org.springframework.ai
+ spring-ai-pgvector-store-spring-boot-starter
+
@@ -94,6 +98,11 @@
ollama
test
+
+ org.springframework.boot
+ spring-boot-docker-compose
+ ${spring-boot-docker-compose.version}
+
@@ -119,6 +128,7 @@
3.4.1
1.0.0-M5
5.9.0
+ 3.1.1
\ No newline at end of file
diff --git a/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/Application.java b/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/Application.java
new file mode 100644
index 000000000000..4cb8a5021e0d
--- /dev/null
+++ b/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/Application.java
@@ -0,0 +1,26 @@
+package com.baeldung.springai.semanticsearch;
+
+import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration;
+import org.springframework.ai.autoconfigure.vectorstore.chroma.ChromaVectorStoreAutoConfiguration;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.ollama.OllamaChatModel;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.context.annotation.PropertySource;
+
+@SpringBootApplication(exclude = { OpenAiAutoConfiguration.class, ChromaVectorStoreAutoConfiguration.class })
+@PropertySource("classpath:application-semantic-search.properties")
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+ @Bean
+ @Primary
+ public ChatModel chatModel(OllamaChatModel ollamaChatModel) {
+ return ollamaChatModel;
+ }
+}
diff --git a/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/Book.java b/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/Book.java
new file mode 100644
index 000000000000..abd7a2a69091
--- /dev/null
+++ b/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/Book.java
@@ -0,0 +1,5 @@
+package com.baeldung.springai.semanticsearch;
+
+public record Book(String title, String author, String description) {
+
+}
diff --git a/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/BookSearchController.java b/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/BookSearchController.java
new file mode 100644
index 000000000000..922c6058011a
--- /dev/null
+++ b/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/BookSearchController.java
@@ -0,0 +1,54 @@
+package com.baeldung.springai.semanticsearch;
+
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.document.Document;
+import org.springframework.ai.vectorstore.SearchRequest;
+import org.springframework.ai.vectorstore.VectorStore;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/books")
+public class BookSearchController {
+
+ private final VectorStore vectorStore;
+ private final ChatClient chatClient;
+
+ public BookSearchController(VectorStore vectorStore, ChatClient.Builder chatClientBuilder) {
+ this.vectorStore = vectorStore;
+ this.chatClient = chatClientBuilder.build();
+ }
+
+ @PostMapping("/search")
+ List semanticSearch(@RequestBody String query) {
+ return vectorStore.similaritySearch(SearchRequest.builder()
+ .query(query)
+ .topK(3)
+ .build())
+ .stream()
+ .map(Document::getText)
+ .toList();
+ }
+
+ @PostMapping("/enhanced-search")
+ String enhancedSearch(@RequestBody String query) {
+ String context = vectorStore.similaritySearch(SearchRequest.builder()
+ .query(query)
+ .topK(3)
+ .build())
+ .stream()
+ .map(Document::getText)
+ .reduce("", (a, b) -> a + b + "\n");
+
+ return chatClient.prompt()
+ .system(context)
+ .user(query)
+ .call()
+ .content();
+ }
+
+}
diff --git a/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/BooksIngestionPipeline.java b/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/BooksIngestionPipeline.java
new file mode 100644
index 000000000000..471d9387d92e
--- /dev/null
+++ b/spring-ai-2/src/main/java/com/baeldung/springai/semanticsearch/BooksIngestionPipeline.java
@@ -0,0 +1,39 @@
+package com.baeldung.springai.semanticsearch;
+
+import jakarta.annotation.PostConstruct;
+
+import org.springframework.ai.document.Document;
+import org.springframework.ai.vectorstore.VectorStore;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+public class BooksIngestionPipeline {
+
+ private final VectorStore vectorStore;
+
+ public BooksIngestionPipeline(VectorStore vectorStore) {
+ this.vectorStore = vectorStore;
+ }
+
+ @PostConstruct
+ void run() {
+ var books = List.of(new Book("The Great Gatsby", "F. Scott Fitzgerald",
+ "The Great Gatsby is a 1925 novel by American writer F. Scott Fitzgerald. Set in the Jazz Age on Long Island, near New York City, the novel depicts first-person narrator Nick Carraway's interactions with mysterious millionaire Jay Gatsby and Gatsby's obsession to reunite with his former lover, Daisy Buchanan."),
+ new Book("To Kill a Mockingbird", "Harper Lee",
+ "To Kill a Mockingbird is a novel by the American author Harper Lee. It was published in 1960 and was instantly successful. In the United States, it is widely read in high schools and middle schools."),
+ new Book("1984", "George Orwell",
+ "Nineteen Eighty-Four: A Novel, often referred to as 1984, is a dystopian social science fiction novel by the English novelist George Orwell. It was published on 8 June 1949 by Secker & Warburg as Orwell's ninth and final book completed in his lifetime."),
+ new Book("The Catcher in the Rye", "J. D. Salinger",
+ "The Catcher in the Rye is a novel by J. D. Salinger, partially published in serial form in 1945–1946 and as a novel in 1951. It was originally intended for adults but is often read by adolescents for its themes of angst, alienation, and as a critique on superficiality in society."),
+ new Book("Lord of the Flies", "William Golding",
+ "Lord of the Flies is a 1954 novel by Nobel Prize-winning British author William Golding. The book focuses on a group of British"));
+
+ List documents = books.stream()
+ .map(book -> new Document(book.toString()))
+ .toList();
+
+ vectorStore.add(documents);
+ }
+}
diff --git a/spring-ai-2/src/main/resources/application-semantic-search.properties b/spring-ai-2/src/main/resources/application-semantic-search.properties
new file mode 100644
index 000000000000..2e02182f9dcf
--- /dev/null
+++ b/spring-ai-2/src/main/resources/application-semantic-search.properties
@@ -0,0 +1,13 @@
+spring.ai.ollama.init.pull-model-strategy=when_missing
+spring.ai.ollama.init.chat.include=true
+spring.ai.ollama.embedding.options.model=nomic-embed-text
+spring.ai.vectorstore.pgvector.initialize-schema=true
+spring.ai.vectorstore.pgvector.dimensions=768
+spring.ai.vectorstore.pgvector.index-type=hnsw
+spring.docker.compose.file=docker-compose.yml
+spring.docker.compose.enabled=true
+spring.datasource.url=jdbc:postgresql://localhost:5434/vectordb
+spring.datasource.username=postgres
+spring.datasource.password=postgres
+spring.datasource.driver-class-name=org.postgresql.Driver
+spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
\ No newline at end of file