Through integration with advanced AI algorithms, vector databases are no longer simple repositories of multidimensional information, but become dynamic platforms for analysis, prediction and making intelligent data-driven decisions. In this article we will see how the Spring AI framework offers a simple and intuitive solution for integrating with vector databases.
Prerequisites
For our tutorial we will use the Qdrant vector database and OpenAI’s “text-embedding-3-small” model to generate multidimensional vectors (embeddings). We therefore invite you to read our previous articles on these topics:
You can also download the source code of our tutorial from GitHub:
Vector databases compatible with Spring AI
Although we decided to use Qdrant in this tutorial, the way integration into Spring AI with vector databases works is still the same. Below is the list of compatible DBs:
You therefore have a wide choice to find the solution that best suits your needs.
Qdrant integration tutorial with Spring AI
Database connection
We begin our tutorial on integrating Qdrant into Spring AI by importing the maven dependency relating to the module that acts as the connector:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qdrant-store-spring-boot-starter</artifactId>
</dependency>
To allow authentication of our application to Qdrant it is necessary to generate an API Key. To do this you need to access the Qdrant Web-UI (as explained in the previous article) and click on the key icon at the top right.
Subsequently, in the popup that will appear you can type a key of your choice:
Once the key has been created, we can proceed with configuring Spring AI. In this regard, it is necessary to add the following lines to the application.properties file:
spring.ai.vectorstore.qdrant.host=localhost
spring.ai.vectorstore.qdrant.port=6334
spring.ai.vectorstore.qdrant.api-key=ewwk1201nqndkq12u14uop
spring.ai.vectorstore.qdrant.collectionname=spring-test-collection
As you can see, apart from the connection parameters (host, port and API Key), we have also defined the name of the collection to which we want to connect.
At this point, trying to start the Spring AI application, the empty collection will automatically be created and it will be possible to view it within the Web-UI.
Save the embeddings in the DB
As we have already seen in our previous tutorial, with OpenAI it is very simple to generate vector representations starting from a string. We therefore proceed by importing the dependencies from the modules:
- “Spring Boot – Web” required for exposing a RestEndpoint
- “Spring AI – OpenAI” required to generate embeddings
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
And we implement a RestController to generate embeddings and insert them into Qdrant:
package com.devturtle.springai.vectordbdemo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OpenAiEmbeddingController {
@Autowired
private VectorStore vectorStore;
@PostMapping("/ai/embeddings/add")
public void add(@RequestBody List<String> docs) {
List<Document> documents = new ArrayList<Document>();
docs.forEach((el) -> {
documents.add(new Document(el));
});
vectorStore.add(documents);
}
}
Once again, the code is really very simple and intuitive:
- we define an endpoint that receives a list of strings in POST;
- for each string we create an object of type Document;
- we use VectorStore to insert documents into the vector database.
In all this we have never referred to OpenAI or Qdrant but Spring AI is able to automatically understand the model and the DB to use as we have imported the dependencies previously (via dependency injection). We could then easily replace both the LLM and the database.
By executing a curl on the newly created endpoint we can verify its functioning.
curl --location 'http://localhost:8080/ai/embeddings/add' \
--header 'Content-Type: application/json' \
--data '[
"We will use the Qdrant vector database",
"With Spring AI we will generate embeddings",
"We will use Qdrant to save the embeddings",
"We will do a similarity search using Qdrant"
]'
By opening the collection via the Qdrant Web-UI we can verify that the data is present:
Perform similarity searches in vector databases
Having inserted the data into the collection, we can now use it to carry out similarity searches. To do this, simply define a second endpoint that takes as input a string to use as a filter for the search:
@GetMapping("ai/embeddings/search")
public List<Document> search(@RequestParam(value = "query") String query) {
return vectorStore.similaritySearch(query);
}
Below is an example of an invocation to the search endpoint:
http://localhost:8080/ai/embeddings/search?query=Quadrant vector database
The result will be:
[
{
"embedding": [
],
"content": "We will use the Qdrant vector database",
"id": "5b4843e6-c9e4-4af0-9e7c-79d113f1d3b9",
"metadata": {
"distance": 0.36218166
}
},
{
"embedding": [
],
"content": "We will do a similarity search using Qdrant",
"id": "1b2a4f99-2be7-4d54-acf6-bc4cceed903f",
"metadata": {
"distance": 0.58939946
}
},
{
"embedding": [
],
"content": "We will use Qdrant to save the embeddings",
"id": "2a6a692e-4b71-4738-9c1e-7d4d709a249e",
"metadata": {
"distance": 0.6111447
}
},
{
"embedding": [
],
"content": "With Spring AI we will generate embeddings",
"id": "3d39f18f-4279-4dc5-aaf2-6552dbb74e8d",
"metadata": {
"distance": 0.80965024
}
}
]
As you can see, in first place (with a lower “distance” value) we find the phrase “We will use the Qdrant vector database” which contains exactly the searched string. Next are those that contain the word “Qdrant” and finally the phrase that does not contain it.
It is possible to set additional search parameters such as a distance limit value:
@GetMapping("ai/embeddings/search")
public List<Document> search(@RequestParam(value = "query") String query) {
return vectorStore.similaritySearch(
SearchRequest.defaults()
.withQuery(query)
.withSimilarityThreshold(0.5));
}
By doing this the query will only return the first result that has a distance value less than 0.5.
As always, I hope that the tutorial was useful in making you understand in a simple way how the integration between Spring AI and vector databases works and I invite you to read the other articles on our blog on similar topics.