DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Enhancing Query Performance With AI and Vector Search in Azure Cosmos DB for PostgreSQL
  • PostgresML: Streamlining AI Model Deployment With PostgreSQL Integration
  • PostgresML: Extension That Turns PostgreSQL Into a Platform for AI Apps
  • Performing and Managing Incremental Backups Using pg_basebackup in PostgreSQL 17

Trending

  • Java Virtual Threads and Scaling
  • Performance Optimization Techniques for Snowflake on AWS
  • Contextual AI Integration for Agile Product Teams
  • How to Format Articles for DZone
  1. DZone
  2. Data Engineering
  3. AI/ML
  4. Getting Started With Spring AI and PostgreSQL PGVector

Getting Started With Spring AI and PostgreSQL PGVector

Learn to build generative AI applications in Java from scratch using Spring AI and PostgreSQL pgvector.

By 
Denis Magda user avatar
Denis Magda
DZone Core CORE ·
Jan. 24, 24 · Tutorial
Likes (8)
Comment
Save
Tweet
Share
10.6K Views

Join the DZone community and get the full member experience.

Join For Free

The Spring AI is a new project of the Spring ecosystem that streamlines the creation of AI applications in Java. By using Spring AI together with PostgreSQL pgvector, you can build generative AI applications that draw insights from your data.

First, this article introduces you to the Spring AI ChatClient that uses the OpenAI GPT-4 model to generate recommendations based on user prompts. Next, the article shows how to deploy PostgreSQL with the PGVector extension and perform vector similarity searches using the Spring AI EmbeddingClient and Spring JdbcClient.

Adding Spring AI Dependency

Spring AI supports many large language model (LLM) providers, with each LLM having its own Spring AI dependency.

Let's assume that you prefer working with OpenAI models and APIs. Then, you need to add the following dependency to a project:

XML
 
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
    <version>{latest.version}</version>
</dependency>


Also, at the time of writing, Spring AI was in active development, with the framework artifacts being released in the Spring Milestone and/or Snapshot repositories. Thus, if you still can't find Spring AI on https://start.spring.io/, then add the repositories to the pom.xml file:

XML
 
<repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>spring-snapshots</id>
      <name>Spring Snapshots</name>
      <url>https://repo.spring.io/snapshot</url>
      <releases>
        <enabled>false</enabled>
      </releases>
    </repository>
</repositories>

Setting Up OpenAI Module

The OpenAI module comes with several configuration properties, allowing the management of connectivity-related settings and fine-tuning the behavior of OpenAI models.

At a minimum, you need to provide your OpenAI API key, which will be used by Spring AI to access GPT and embedding models. Once the key is created, add it to the application.properties file:

Properties files
 
spring.ai.openai.api-key=sk-...


Then, if necessary, you can select particular GPT and embedding models:

Properties files
 
spring.ai.openai.chat.model=gpt-4
spring.ai.openai.embedding.model=text-embedding-ada-002


In the end, you can test that the OpenAI module is configured properly by implementing a simple assistant with Spring AI's ChatClient:

Java
 
// Inject the ChatClient bean
@Autowired
private ChatClient aiClient;

// Create a system message for ChatGPT explaining the task
private static final SystemMessage SYSTEM_MESSAGE = new SystemMessage(
    """
    You're an assistant who helps to find lodging in San Francisco.
    Suggest three options. Send back a JSON object in the format below.
    [{\"name\": \"<hotel name>\", \"description\": \"<hotel description>\", \"price\": <hotel price>}]
    Don't add any other text to the response. Don't add the new line or any other symbols to the response. Send back the raw JSON.
    """);

public void searchPlaces(String prompt) {
    // Create a Spring AI prompt with the system message and the user message
    Prompt chatPrompt = new Prompt(List.of(SYSTEM_MESSAGE, new UserMessage(prompt)));

    // Send the prompt to ChatGPT and get the response
    ChatResponse response = aiClient.generate(chatPrompt);

    // Get the raw JSON from the response and print it
    String rawJson = response.getGenerations().get(0).getContent();

    System.out.println(rawJson);
}


For the sake of the experiment, if you pass the "I'd like to stay near the Golden Gate Bridge" prompt, then the searchPlaces the method might provide lodging recommendations as follows:

JSON
 
[
 {"name": "Cavallo Point", "description": "Historic hotel offering refined rooms, some with views of the Golden Gate Bridge, plus a spa & dining.", "price": 450}, 
 {"name": "Argonaut Hotel", "description": "Upscale, nautical-themed hotel offering Golden Gate Bridge views, plus a seafood restaurant.", "price": 300}, 
 {"name": "Hotel Del Sol", "description": "Colorful, retro hotel with a pool, offering complimentary breakfast & an afternoon cookies reception.", "price": 200}
]

Starting Postgres With PGVector

If you run the previous code snippet with the ChatClient, you'll notice that it usually takes over 10 seconds for the OpenAI GPT model to generate a response. The model has a broad and deep knowledge base, and it takes time to produce a relevant response.

Apart from the high latency, the GPT model might not have been trained on data that is relevant to your application workload. Thus, it might generate responses that are far from being satisfactory for the user.

However, you can always expedite the search and provide users with accurate responses if you generate embeddings on a subset of your data and then let Postgres work with those embeddings.

The pgvector extension allows storing and querying vector embeddings in Postgres. The easiest way to start with PGVector is by starting a Postgres instance with the extension in Docker:

Shell
 
mkdir ~/postgres-volume/

docker run --name postgres \
    -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=password \
    -p 5432:5432 \
    -v ~/postgres-volume/:/var/lib/postgresql/data -d ankane/pgvector:latest


Once started, you can connect to the container and enable the extension by executing the CREATE EXTENSION vector statement: 

Shell
 
docker exec -it postgres psql -U postgres -c 'CREATE EXTENSION vector'


 Lastly, add the Postgres JDBC driver dependency to the pom.xml file:

XML
 
<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
  <version>{latest.version}</version>
</dependency>


Configure the Spring DataSource by adding the following settings to the application.properties file:

Properties files
 
spring.datasource.url = jdbc:postgresql://127.0.0.1:5432/postgres
spring.datasource.username = postgres
spring.datasource.password = password

Performing Vector Similarity Search With Spring AI

At a minimum, the vector similarity search is a two-step process.

First, you need to use an embedding model to generate a vector/embedding for a provided user prompt or other text. Spring AI supports the EmbeddingClient that connects to OpenAI's or other providers' embedding models and generates a vectorized representation for the text input:

Java
 
// Inject the Spring AI Embedding client
@Autowired
private EmbeddingClient aiClient;

public List<Place> searchPlaces(String prompt) {
    // Use the Embedding client to generate a vector for the user prompt
    List<Double> promptEmbedding = aiClient.embed(prompt);
    ...
}


Second, you use the generated embedding to perform a similarity search across vectors stored in the Postgres database. For instance, you can use the Spring JdbcClient for this task:

Java
 
@Autowired
private JdbcClient jdbcClient;

// Inject the Spring AI Embedding client
@Autowired
private EmbeddingClient aiClient;


public List<Place> searchPlaces(String prompt) {
    // Use the Embedding client to generate a vector for the user prompt
    List<Double> promptEmbedding = aiClient.embed(prompt);

    // Perform the vector similarity search
    StatementSpec query = jdbcClient.sql(
        "SELECT name, description, price " +
        "FROM airbnb_listing WHERE 1 - (description_embedding <=> :user_promt::vector) > 0.7 " +
        "ORDER BY description_embedding <=> :user_promt::vector LIMIT 3")
        .param("user_promt", promptEmbedding.toString());

    // Return the recommended places
    return query.query(Place.class).list();
}


  • The description_embedding column stores embeddings that were pre-generated for Airbnb listing overviews from the description column. The Airbnb embeddings were produced by the same model that is used by Spring AI's EmbeddingClient for the user prompts.
  • Postgres uses PGVector to calculate the cosine distance (<=>) between the Airbnb and user prompt embeddings (description_embedding <=> :user_prompt::vector) and then returns only those Airbnb listings whose description is > 0.7 similar to the provided user prompt. The similarity is measured as a value in the range from 0 to 1. The closer the similarity to 1, the more related the vectors are.

What's Next

Spring AI and PostgreSQL PGVector provide all the essential capabilities needed for building generative AI applications in Java. If you're curious to learn more, watch this hands-on tutorial. It guides you through the process of creating a lodging recommendation service in Java from scratch, optimizing similarity searches with specialized indexes, and scaling with distributed Postgres (YugabyteDB):


AI PostgreSQL Spring Integration

Opinions expressed by DZone contributors are their own.

Related

  • Enhancing Query Performance With AI and Vector Search in Azure Cosmos DB for PostgreSQL
  • PostgresML: Streamlining AI Model Deployment With PostgreSQL Integration
  • PostgresML: Extension That Turns PostgreSQL Into a Platform for AI Apps
  • Performing and Managing Incremental Backups Using pg_basebackup in PostgreSQL 17

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!