Spring Ai Redis Vector Store Custom Configuration With Jedis

The Spring Ai Redis Vector Store Custom Configuration With Jedis allows to customize the Redis Vector Store, by default, the Spring Ai Redis Vector Store provides default values for a lot of parameters, such as indexName, prefix, initializeSchema, vectorAlgorithm, batchingStrategy, contentFieldName, metadataFields, which will work fine for most of the cases, but if required. we can customize the Redis Vector Store as per the application requirement.

package com.example.springai.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class SpringAiController {

    private final ChatClient chatClient;

    @Autowired
    private VectorStore redisVectorStore;

    public SpringAiController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/redisVectorStore")
    public String redisVectorStore(@RequestParam(value = "question", defaultValue = "What is Spring Framework?") String question) {
        ChatResponse response = chatClient.prompt()
                .advisors(new QuestionAnswerAdvisor(redisVectorStore))
                .user(question)
                .call()
                .chatResponse();
        return response.getResult().getOutput().getContent();
    }

    @GetMapping("/redisVectorStoreSimilaritySearch")
    public List<Document> redisVectorStoreSimilaritySearch(@RequestParam(value = "question", defaultValue = "What is Spring Framework?") String question) {
        List<Document> results = redisVectorStore.similaritySearch(SearchRequest.builder()
                .query(question)
                .topK(5)
                .similarityThresholdAll()
                .build());
        return results;
    }
}
package com.example.springai;

import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.reader.ExtractedTextFormatter;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.redis.RedisVectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource;
import redis.clients.jedis.JedisPooled;

@SpringBootApplication
public class SpringAiApplication {
    @Value("classpath:/docs/spring-faq.pdf")
    private Resource pdfResource;
    @Value("${spring.ai.vectorstore.redis.port}")
    private int redisPort;
    @Value("${spring.ai.vectorstore.redis.uri}")
    private String redisUri;
    @Value("${spring.ai.vectorstore.redis.index}")
    private String redisIndex;
    @Value("${spring.ai.vectorstore.redis.prefix}")
    private String redisPrefix;
    @Value("${spring.ai.vectorstore.redis.embeddingFieldName}")
    private String redisEmbeddingFieldName;
    @Value("${spring.ai.vectorstore.redis.contentFieldName}")
    private String redisContentFieldName;
    @Value("${spring.ai.vectorstore.redis.initialize-schema}")
    private boolean redisInitializeSchema;


    @Autowired
    private VectorStore vectorStore;
    @Autowired
    private EmbeddingModel embeddingModel;

    public static void main(String[] args) {
        SpringApplication.run(SpringAiApplication.class, args);
    }

    @Bean
    VectorStore redisVectorStore() {
        System.out.println("SpringAiApplication.redisVectorStore");
        PagePdfDocumentReader pdfReader = new PagePdfDocumentReader(pdfResource, PdfDocumentReaderConfig.builder()
                .withPageExtractedTextFormatter(ExtractedTextFormatter.builder()
                        .withNumberOfBottomTextLinesToDelete(3)
                        .withNumberOfTopPagesToSkipBeforeDelete(1)
                        .build())
                .withPagesPerDocument(1)
                .build());
        var tokenTextSplitter = new TokenTextSplitter();
        RedisVectorStore vectorStore = RedisVectorStore.builder(jedisPooled(), embeddingModel)
                .indexName(redisIndex)
                .prefix(redisPrefix)
                .initializeSchema(redisInitializeSchema)
                .vectorAlgorithm(RedisVectorStore.Algorithm.HSNW)
                .batchingStrategy(new TokenCountBatchingStrategy())
                .contentFieldName(redisContentFieldName)
                .metadataFields(RedisVectorStore.MetadataField.tag("spring"), RedisVectorStore.MetadataField.numeric("year"), RedisVectorStore.MetadataField.text("description"))
                .build();
        vectorStore.accept(tokenTextSplitter.apply(pdfReader.get()));
        return vectorStore;
    }

    @Bean
    public JedisPooled jedisPooled() {
        JedisPooled jedisPooled = new JedisPooled(redisUri, redisPort);
        return jedisPooled;
    }
}
spring.application.name=SpringAi
spring.docker.compose.lifecycle-management=start-only
spring.threads.virtual.enabled=true
spring.ai.vectorstore.redis.uri=localhost
spring.ai.vectorstore.redis.port=6379
spring.ai.vectorstore.redis.index=spring-ai-redis-index
spring.ai.vectorstore.redis.prefix=spring-ai-redis-embedding
spring.ai.vectorstore.redis.embeddingFieldName=spring-ai-redis-custom-embedding
spring.ai.vectorstore.redis.contentFieldName=spring-ai-redis-custom-content
spring.ai.vectorstore.redis.initialize-schema=true
# The default Ollama Model in Spring Ai is mistral, but it can be changed by setting the below property. make sure to download the same model in entrypoint.sh file
#spring.ai.ollama.chat.options.model=llama3.1
spring.ai.ollama.embedding.model=mistral
# If running the Ollama Docker Instance separately, then set this property
spring.docker.compose.enabled=false
services:
  ollama-model:
    image: ollama/ollama:latest
    container_name: ollama_container
    ports:
      - 11434:11434/tcp
    healthcheck:
      test: ollama --version || exit 1
    command: serve
    volumes:
      - ./ollama/ollama:/root/.ollama
      - ./entrypoint.sh:/entrypoint.sh
    pull_policy: missing
    tty: true
    restart: no
    entrypoint: [ "/usr/bin/bash", "/entrypoint.sh" ]

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open_webui_container
    environment:
      WEBUI_AUTH: false
    ports:
      - "8081:8080"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - open-webui:/app/backend/data
    restart: no

  redis:
    image: redislabs/redismod
    container_name: redislabs_container
    restart: always
    ports:
      - "6379:6379"

  #  in redis-insight ui, add host name as redis
  redis-insight:
    image: redis/redisinsight:latest
    container_name: redis_insight_container
    restart: always
    ports:
      - '5540:5540'
    volumes:
      - redisinsight_db:/db

volumes:
  open-webui:
  redisinsight_db:
#!/bin/bash
# Start Ollama in the background.
/bin/ollama serve &
# Record Process ID.
pid=$!
# Pause for Ollama to start.
sleep 5
# The default Ollama Model in Spring Ai is mistral, but it can be changed in the applications property file. Make sure to download the same Model here
echo "🔴 Retrieve LLAMA3 model..."
ollama pull mistral
echo "🟢 Done!"
# Wait for the Ollama process to finish.
wait $pid
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.2</version>
        <relativePath/>
    </parent>
    <groupId>com.example.springai</groupId>
    <artifactId>redis-vector-store-custom-configuration-with-jedis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Redis Vector Store Custom Configuration With Jedis</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>21</java.version>
        <spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-redis-store-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-pdf-document-reader</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-docker-compose</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.example.springai.SpringAiApplication</mainClass>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <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>
</project>

Open http://localhost:5540/ to log in to Redis Insight, add the hostname as Redis, and leave the username and password blank.

Run the curl to see the Spring Ai Redis Vector Store Custom Configuration With Jedis

curl --location 'localhost:8080/redisVectorStore'
curl --location 'localhost:8080/redisVectorStoreSimilaritySearch'

follow us on