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

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Leverage Amazon BedRock Chat Model With Java and Spring AI
  • Unlocking the Power of Serverless AI/ML on AWS: Expert Strategies for Scalable and Secure Applications
  • Building Intelligent Microservices With Go and AWS AI Services
  • Generate Unit Tests With AI Using Ollama and Spring Boot

Trending

  • Navigating Double and Triple Extortion Tactics
  • Developers Beware: Slopsquatting and Vibe Coding Can Increase Risk of AI-Powered Attacks
  • Operational Principles, Architecture, Benefits, and Limitations of Artificial Intelligence Large Language Models
  • How To Build Resilient Microservices Using Circuit Breakers and Retries: A Developer’s Guide To Surviving
  1. DZone
  2. Data Engineering
  3. AI/ML
  4. Context Search With AWS Bedrock, Cohere Model, and Spring AI

Context Search With AWS Bedrock, Cohere Model, and Spring AI

In this article, learn how to build a simple Java application using Spring AI and Amazon Bedrock to generate and compare text embeddings with Cohere’s Embed Multilingual v3 model.

By 
Danil Temnikov user avatar
Danil Temnikov
DZone Core CORE ·
Bhanuprakash Madupati user avatar
Bhanuprakash Madupati
·
Apr. 09, 25 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
5.9K Views

Join the DZone community and get the full member experience.

Join For Free

Today, we will create simple applications using the Cohere Embed Multilingual v3 model via Amazon Bedrock and Spring AI.

We’ll skip over basic Spring concepts like bean management and starters, as the main goal of this article is to explore the capabilities of Spring AI and Amazon Bedrock.

The full code for this project is available in the accompanying GitHub repository. To keep this article concise, I won’t include some pre-calculated values and simple POJOs here — you can find them in the repo if needed.

What Are Embeddings?

Before we start code implementation, let's discuss embeddings.

In the Spring AI documentation, we find the following definition of embeddings:

"Embeddings are numerical representations of text, images, or videos that capture relationships between inputs."

Embeddings convert text, images, and video into arrays of floating-point numbers called vectors. These vectors are designed to capture the meaning of the text, images, and videos. The length of the embedding array is called the vector’s dimensionality.

Key points we should pay attention to:

  1. Numerical representation of text (also applicable for images and videos, but let’s focus just on texts in this article)
  2. Embeddings are vectors. And as every vector has coordinates for each dimension it exists, we should think about embeddings as a coordinate of our input in “Text Universe”

As with every other vector, we can find the distance between two embeddings. The closer the two embeddings are to each other, the more similar their context. We will use this approach in our application. 

Determining the Scope of Our Future Application

Let’s imagine that we have an online shop with different mattresses. Every single item has its ID and description. We need to create a module, that will receive users input describing the item the user wants to find or buy and returns 5 most relevant products to this query.

We will achieve this goal using embeddings. Steps we need to implement

  1. We will fetch embeddings (vector representation) of our existing products and store them. I’ll not show this step in this article because it will be similar to one we will explore later. But you can find precalculated embeddings to use in your code in the GitHub repo I previously shared.
  2. We will call the Amazon Bedrock embeddings API for each user input.
  3. We will compare user input embeddings with precalculated embeddings of our item description. We will leverage the Cosine Similarity approach to find the closest vectors.

Implementation

Note: Please be aware that executing this application may cost you some money for running AWS Bedrock.

Step 1. Generate AWS Keys and Enable the Foundational Model

If you don’t have an active AWS access key, do the following steps (copied and pasted from this SOF thread):

  1. Go to: http://aws.amazon.com/
  2. Sign up and create a new account (they'll give you the option for a 1-year trial or similar)
  3. Go to your AWS account overview
  4. Account menu in the upper-right (has your name on it)
  5. sub-menu: Security Credentials

After you have your keys generated you should choose and enable the foundational model in Bedrock. Go to Amazon Bedrock, and from the Model Access menu on the left, configure access to the Cohere Embed Multilingual model. 

Step 2. Set Up a Project

To quickly generate a project template with all necessary dependencies, one may use https://start.spring.io/ 

In our example, we’ll be using Java 17 and Spring Boot 3.4.1. Also, we need to include the following dependency:

Amazon Bedrock: This dependency provides us with smooth integration with Amazon Bedrock just by writing a couple lines of code and a few lines of configurations.

After clicking generate, open the downloaded files in the IDE you are working on, and validate that all necessary dependencies exist in pom.xml.

XML
 
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-bedrock-ai-spring-boot-starter</artifactId>
  <version>1.0.0-M6</version>
</dependency>

<dependencyManagement>
  <dependencies>
     <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-bom</artifactId>
        <version>1.0.0-M6</version>
        <type>pom</type>
        <scope>import</scope>
     </dependency>
  </dependencies>
</dependencyManagement>


At the moment of writing this article, Spring AI version 1.0.0-M6 has not yet been published in the central Maven repository and is only available in the Spring repository. That’s why we need to add a link to that repo in our pom.xml as well:

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


Step 3. Set Up the Configuration File

As a next step, we need to configure our property file. By default, Spring uses application.yaml or application.properties file. In this example, I’m using the YAML format. You may reformat code into .properties if you feel more comfortable working with this format.

Here are all the configs we need to add to the application.yaml file:

YAML
 
spring:
 application:
   name: aiembeddingsbedrock
 ai:
   bedrock:
     aws:
       access-key: 
       secret-key: 
     cohere:
       embedding:
         model: cohere.embed-multilingual-v3
         enabled: true


Access-key, secret-key 

Copy and paste the security credential pair we generated in step 1. Make sure you are not pushing these credentials to the remote repo. 

Model

We will be using cohere.embed-multilingual-v3. We may also use the Titan embedding model, but in this case, the config file should be set in a slightly different way. You may find more information in the Spring AI docs.

As the main purpose of this article is to show the ease of Spring AI integration with Amazon Bedrock embedding models, we will not go deeper into other configurations. You may find more config options in the Spring docs.

Step 4. Create Resource Files

Let’s create two files in the resource folder. 

The first one is the JSON-formatted “database” of items in our shop. Every item will have the following parameters: Id, Name, and Description. I named this file samples.json and saved it in the resource folder. 

JSON
 
[
 {
   "id": 1,
   "name": "DreamSoft Memory Foam",
   "description": "Queen size, memory foam, medium firmness, cooling gel layer, hypoallergenic cover, pressure-relieving design, motion isolation, anti-bacterial protection, reinforced edges, eco-friendly materials, breathable fabric."
 },
 {
   "id": 2,
   "name": "SleepWell Hybrid Comfort",
   "description": "King size, hybrid (foam + springs), medium-firm, breathable fabric, motion isolation, orthopedic support, reinforced edges, dust-mite resistant, zoned pressure relief, temperature-regulating cover, moisture-wicking material."
 },
 {
   "id": 3,
   "name": "OrthoRest Firm Support",
   "description": "Full size, high-density foam, firm support, orthopedic design, anti-bacterial cover, hypoallergenic materials, motion isolation, lumbar support zone, durable construction, soft knit fabric."
 },
 {
   "id": 4,
   "name": "CloudNine Plush Top",
   "description": "California King, pillow-top design, soft firmness, pocketed coils, moisture-wicking fabric, pressure-relief zones, motion isolation, anti-microbial treatment, reinforced edge support, luxury plush feel."
 },
 {
   "id": 5,
   "name": "EcoSleep Organic Latex",
   "description": "Queen size, natural latex, medium firmness, organic cotton cover, eco-friendly materials, hypoallergenic, durable support, breathable construction, cooling airflow design, anti-dust-mite protection."
 },
 {
   "id": 6,
   "name": "ZenBalance Hybrid Pro",
   "description": "King size, hybrid latex and springs, firm support, pressure relief zones, cooling technology, orthopedic certified, reinforced lumbar support, anti-bacterial protection, soft-touch fabric, edge stability."
 },
 {
   "id": 7,
   "name": "SnugFit Dual Comfort",
   "description": "Twin size, reversible (soft and firm sides), gel-infused memory foam, anti-microbial cover, motion isolation, breathable materials, cooling effect, ergonomic design, pressure relief, durable construction."
 },
 {
   "id": 8,
   "name": "TranquilDream Euro Top",
   "description": "Full size, euro-top cushion, medium-soft, breathable layers, reinforced edges, plush comfort, pressure relief, orthopedic support, anti-allergy treatment, soft-touch fabric."
 },
 {
   "id": 9,
   "name": "SleepWell Firm Hybrid",
   "description": "Queen size, pocket springs and latex, extra firm support, temperature-regulating fabric, breathable mesh cover, motion isolation, reinforced lumbar zone, anti-microbial coating, edge support, durable foam layers."
 },
 {
   "id": 10,
   "name": "CloudNest Ultra Soft",
   "description": "Twin size, ultra-soft memory foam, adaptive contouring, hypoallergenic materials, plush comfort, ergonomic design, motion isolation, cooling gel layer, anti-dust-mite treatment, durable cover."
 },
 {
   "id": 11,
   "name": "GrandRest Luxury Foam",
   "description": "California King, high-resilience foam, medium firmness, pressure-relieving layers, durable support, orthopedic comfort, breathable construction, anti-allergy cover, moisture-wicking fabric, reinforced durability."
 },
 {
   "id": 12,
   "name": "NatureSleep Bamboo Bliss",
   "description": "Queen size, bamboo-infused foam, medium-plush, dust-mite resistant, cooling effect, eco-friendly construction, breathable layers, ergonomic support, anti-bacterial finish, luxury feel."
 },
 {
   "id": 13,
   "name": "BackCare OrthoFlex",
   "description": "King size, orthopedic support, extra firm, reinforced lumbar zone, breathable mesh cover, motion isolation, pressure-relief technology, anti-allergy fabric, durable construction, anti-microbial treatment."
 },
 {
   "id": 14,
   "name": "EcoHaven Pure Latex",
   "description": "Full size, 100% natural latex, firm support, moisture-resistant organic cotton cover, eco-friendly production, anti-bacterial protection, breathable layers, ergonomic support, durable edge reinforcement, motion control."
 },
 {
   "id": 15,
   "name": "SereneNight Cooling Gel",
   "description": "Twin XL, gel-infused foam, medium-soft, anti-sag technology, eco-friendly fabric, breathable layers, reinforced edges, motion isolation, cooling airflow, pressure relief."
 },
 {
   "id": 16,
   "name": "AirFlow Tech Hybrid",
   "description": "King size, hybrid springs and foam, airflow channels, medium-firm, ergonomic design, orthopedic support, durable frame, anti-bacterial cover, temperature control, reinforced edge support."
 },
 {
   "id": 17,
   "name": "HavenCloud Orthopedic",
   "description": "Queen size, orthopedic memory foam, medium firmness, zoned pressure relief, anti-bacterial fabric, motion isolation, breathable construction, hypoallergenic, edge reinforcement, moisture control."
 },
 {
   "id": 18,
   "name": "EliteRest Plush Feel",
   "description": "California King, plush top layer, responsive foam, moisture-wicking fabric, ultra-soft finish, ergonomic design, breathable mesh, motion control, reinforced edges, luxury feel."
 },
 {
   "id": 19,
   "name": "SleepGuard Anti-Allergy",
   "description": "Full size, hypoallergenic foam, medium-firm, mite-resistant, reinforced support core, anti-dust-mite treatment, breathable design, motion isolation, ergonomic shape, cooling effect."
 },
 {
   "id": 20,
   "name": "SnuggleEase Memory Cloud",
   "description": "Twin size, cloud-like memory foam, medium-plush, heat-dissipating layers, soft knit cover, motion isolation, breathable fabric, anti-bacterial treatment, ergonomic shape, pressure relief."
 }


The second one is a list of embeddings of the product description. I executed embeddings API in a separate application and saved responses for every single product into a separate file, embeddings.json. I’ll not share the whole file here, as it will make the article unreadable, but you still can download it from the GitHub repo of this project I shared at the beginning of the article.

Step 5. Create Embeddings Service

Now, let’s create the main service of our application -> embedding service.

To integrate our application with the embeddings API, we need to autowire EmbeddingModel. We have already configured Bedrock embeddings in the application.yaml. Spring Boot will automatically create and configure the instance (Bean) of EmbeddingModel. 

To fetch embeddings for a particular String or text, we just need to write one line of code:

Java
 
EmbeddingResponse embeddingResponse = embeddingModel.embedForResponse(List.of(text));


Let’s see what the whole service looks like:

Java
 
@Service
public class EmbeddingsService {

   private static List<Product> productList = new ArrayList<>();
   private static Map<Integer, float[]> embeddings = new HashMap<>();

   @Autowired
   private EmbeddingModel embeddingModel;

   @Autowired
   private SimilarityCalculator similarityCalculator;

   @PostConstruct
   public void initProducts() throws IOException {
       ObjectMapper objectMapper = new ObjectMapper();
       InputStream inputStream = getClass().getClassLoader().getResourceAsStream("samples.json");
       if (inputStream != null) {
           // map JSON into List<Product>
           productList = objectMapper.readValue(inputStream, new TypeReference<List<Product>>() {
           });
           System.out.println("Products loaded: List size = " + productList.size());

       } else {
           System.out.println("File samples.json not found in resources.");
       }
       embeddings = loadEmbeddingsFromFile();
   }

   public Map<Integer, float[]> loadEmbeddingsFromFile() {
       try {
           InputStream inputStream = getClass().getClassLoader().getResourceAsStream("embeddings.json");
           ObjectMapper objectMapper = new ObjectMapper();
           return objectMapper.readValue(inputStream, new TypeReference<Map<Integer, float[]>>() {
           });
       } catch (Exception e) {
           System.err.println("Error loading embeddings from file: " + e.getMessage());
           return null;
       }
   }

   public void getSimilarProducts(String query) {
       EmbeddingResponse embeddingResponse = embeddingModel.embedForResponse(List.of(query));
       List<ProductSimilarity> topSimilarProducts = similarityCalculator.findTopSimilarProducts(embeddingResponse.getResult().getOutput(),
               embeddings,
               productList,
               5);
       for (ProductSimilarity ps : topSimilarProducts) {
           System.out.printf("Product ID: %d, Name: %s, Description: %s, Similarity: %.4f%n",
                   ps.getProduct().getId(),
                   ps.getProduct().getName(),
                   ps.getProduct().getDescription(),
                   ps.getSimilarity());
       }
   }


Let’s deep dive into this code:

  1. In the @postconstruct method, we are loading our resources into collections. The list of Products reads our products from samples.json. The product is a POJO with ID, name, and description fields. We also load precalculated embeddings of our products from another file  embeddings.json. We will need these embeddings later when we look for the most similar product.
  2. The most important method in our service is getSimilarProducts which will receive user queries, fetch its embeddings using embeddingModel, and calculate similarities with our existing products. We will take a closer look at similarityCalculator.findTopSimilarProductsa little bit later in this article. After receiving a list of similarities, we will print the top N similar products in the following format:
    • Product ID, Name, Description, Similarity (a number between 0 and 1)

To calculate similarities, we introduced SimilarityCalculator Service. Let’s take a deeper look at its implementation.

Java
 
@Service
public class SimilarityCalculator {

   public float calculateCosineSimilarity(float[] vectorA, float[] vectorB) {
       float dotProduct = 0.0f;
       float normA = 0.0f;
       float normB = 0.0f;

       for (int i = 0; i < vectorA.length; i++) {
           dotProduct += vectorA[i] * vectorB[i];
           normA += Math.pow(vectorA[i], 2);
           normB += Math.pow(vectorB[i], 2);
       }

       return (float) (dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)));
   }

   public List<ProductSimilarity> findTopSimilarProducts(
           float[] queryEmbedding,
           Map<Integer, float[]> embeddings,
           List<Product> products,
           int topN) {

       List<ProductSimilarity> similarities = new ArrayList<>();

       for (Product product : products) {
           float[] productEmbedding = embeddings.get(product.getId());
           if (productEmbedding != null) {
               float similarity = calculateCosineSimilarity(queryEmbedding, productEmbedding);
               similarities.add(new ProductSimilarity(product, similarity));
           }
       }

       return similarities.stream()
               .sorted((p1, p2) -> Double.compare(p2.getSimilarity(), p1.getSimilarity()))
               .limit(topN)
               .toList();
   }


  1. ProductSimilarity is a POJO class containing Product and similarity fields. You can find the code for this class in the GitHub repo.
  2. calculateCosineSimilarity is the method used to find the most similar descriptions to user queries. Cosine similarity is one of the most popular ways to measure the similarity between embeddings. Explaining the exact workings of cosine similarity is beyond the scope of this article.
  3. findTopSimilarProducts is a method called from our embedding service. It calculates similarities with all products, sorts them, and returns the top N products with the highest similarity.

Step 5: Execute Application

We will execute this application directly from code without using any Rest Controllers and API calls. If you want to make this app a little bit more flexible by triggering it by an endpoint execution you may use an approach similar to the one used in this article.

Java
 
@SpringBootApplication
public class AiEmbeddingsApplication {

  public static void main(String[] args) {

     ConfigurableApplicationContext run = new SpringApplicationBuilder(AiEmbeddingsApplication.class)
           .web(WebApplicationType.NONE)
           .run(args);
     run.getBean(EmbeddingsService.class).getSimilarProducts("anti-allergy king-size mattress");
  }


We are executing our code in the last line of the method, fetching the bean from the context and executing the getSimilarProducts method with a provided query. 

In our query, we’ve included 3 keywords: anti-allergy, king-size, mattress. Let’s execute our code and validate the result.

To start our application, we need to run the following command:

  • mvn spring-boot:run

In a couple of seconds after executing, we may see the following result in the console:

Shell
 
Product ID: 13, Name: BackCare OrthoFlex, Description: King size, orthopedic support, extra firm, reinforced lumbar zone, breathable mesh cover, motion isolation, pressure-relief technology, anti-allergy fabric, durable construction, anti-microbial treatment., Similarity: 0,6107
Product ID: 16, Name: AirFlow Tech Hybrid, Description: King size, hybrid springs and foam, airflow channels, medium-firm, ergonomic design, orthopedic support, durable frame, anti-bacterial cover, temperature control, reinforced edge support., Similarity: 0,5984
Product ID: 2, Name: SleepWell Hybrid Comfort, Description: King size, hybrid (foam + springs), medium-firm, breathable fabric, motion isolation, orthopedic support, reinforced edges, dust-mite resistant, zoned pressure relief, temperature-regulating cover, moisture-wicking material., Similarity: 0,5964
Product ID: 5, Name: EcoSleep Organic Latex, Description: Queen size, natural latex, medium firmness, organic cotton cover, eco-friendly materials, hypoallergenic, durable support, breathable construction, cooling airflow design, anti-dust-mite protection., Similarity: 0,5874
Product ID: 1, Name: DreamSoft Memory Foam, Description: Queen size, memory foam, medium firmness, cooling gel layer, hypoallergenic cover, pressure-relieving design, motion isolation, anti-bacterial protection, reinforced edges, eco-friendly materials, breathable fabric., Similarity: 0,5836


We can see that Product 13 has the highest similarity, as it is both a king-sized and hypoallergenic mattress. Even though it doesn't exactly match the search query, it closely aligns with what we were looking for. All of the other recommended mattresses are either king-sized or hypoallergenic.

Conclusion

Spring AI is a great tool that helps developers smoothly integrate with different AI models. At the moment of writing this article, Spring AI supports 10 embedding models, including but not limited to Ollama and Open AI. On the other hand, Amazon Bedrock offers a choice of high-performing foundation models (FMs) from leading AI companies like AI21 Labs, Anthropic, Cohere, DeepSeek, Luma, Meta, Mistral AI, poolside (coming soon), Stability AI, and Amazon through a single API, along with a broad set of capabilities you need to build generative AI applications with security, privacy, and responsible AI.

I hope you found this article helpful and that it will inspire you to explore Spring AI and AWS Bedrock more deeply.

AI AWS Spring Boot

Opinions expressed by DZone contributors are their own.

Related

  • Leverage Amazon BedRock Chat Model With Java and Spring AI
  • Unlocking the Power of Serverless AI/ML on AWS: Expert Strategies for Scalable and Secure Applications
  • Building Intelligent Microservices With Go and AWS AI Services
  • Generate Unit Tests With AI Using Ollama and Spring Boot

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!