Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ADVANCE-RAG

ADVANCE-RAG is a local, configurable Retrieval-Augmented Generation (RAG) service built with Java 21, Spring Boot, Spring AI, Ollama, Qdrant, and Kafka. It ingests PDF documents asynchronously, extracts and chunks their contents, indexes searchable representations, and answers questions using only retrieved context.

The project is designed as an understandable reference implementation: each major RAG stage has its own package and can be configured independently. The default local runtime is Ollama for generation and embeddings, Qdrant for vector search, an in-memory BM25 index for lexical search, and Kafka for asynchronous ingestion.

Contents

What the application does

  1. Accepts a PDF and optional document metadata through a REST endpoint.
  2. Saves the upload locally and sends a small ingestion event to Kafka.
  3. A Kafka consumer extracts PDF pages with Apache Tika.
  4. The configured chunking strategy splits pages into searchable chunks.
  5. The service creates chunk vectors plus title, summary, and keyword representations.
  6. Qdrant stores dense vectors; an in-memory BM25 index stores lexical terms.
  7. For a question, the service applies query transformations, filters, hybrid retrieval, optional multi-hop retrieval, parent-child expansion, reranking, and context compression.
  8. Ollama receives the compact retrieved context and returns a grounded answer with citations.

Architecture and request flow

PDF upload
  -> local staging area
  -> Kafka ingestion event
  -> Tika PDF extraction
  -> metadata enrichment
  -> configured chunking strategy
  -> child chunks + multi-vector representations
  -> Qdrant dense index + in-memory BM25 index

Question + optional filters
  -> query transformation
  -> metadata/access filtering
  -> Qdrant semantic search + BM25 keyword search
  -> RRF or weighted rank fusion
  -> optional multi-hop search
  -> parent-document expansion
  -> reranking
  -> context compression
  -> Ollama answer generation
  -> answer + citations

The detailed editable flow diagram is available in the docs folder.

Project structure

ADVANCE-RAG/
├── compose.yaml                         # Qdrant, Kafka, and optional provider containers
├── pom.xml                              # Maven dependencies and Java 21 build configuration
├── README.md                            # This guide
├── docs/
│   └── <flow-diagram>.drawio            # Editable end-to-end flow diagram
├── data/
│   └── uploads/                         # Created at runtime; staged PDF uploads
└── src/
    └── main/
        ├── java/com/advance/rag/
        │   ├── AdvanceRagApplication.java    # Spring Boot entry point; enables Kafka
        │   ├── api/controller/               # REST endpoints
        │   │   ├── RagController.java        # PDF ingestion, job status, and question APIs
        │   │   └── ProviderController.java   # Active provider selection API
        │   ├── chunking/                     # Configurable document splitting strategies
        │   │   ├── config/                   # Chunking settings model
        │   │   ├── core/                     # Strategy contract and shared utilities
        │   │   ├── service/                  # Strategy selection service
        │   │   └── strategy/
        │   │       ├── basic/                # Default, fixed-size, sliding-window
        │   │       ├── structural/           # Recursive, paragraph, sentence, hierarchy
        │   │       └── contentaware/         # Semantic, Markdown, table, code aware
        │   ├── config/                       # Provider selection configuration model
        │   ├── exception/                    # Consistent REST error handling
        │   ├── ingestion/                    # Kafka-backed asynchronous PDF ingestion
        │   ├── model/                        # API, ingestion, metadata, and retrieval records
        │   ├── observability/                # Micrometer RAG metrics
        │   ├── provider/                     # Provider gateway and connection definitions
        │   │   ├── gateway/
        │   │   ├── llm/                      # Ollama, LocalAI, vLLM definitions
        │   │   └── vector/                   # Qdrant, Chroma, Milvus definitions
        │   ├── rag/                          # End-to-end RAG orchestration service
        │   └── retrieval/                    # Retrieval quality pipeline
        │       ├── compression/              # Query-aware context compression
        │       ├── filter/                   # Metadata/access filter translation
        │       ├── hybrid/                   # Dense + BM25 fusion
        │       ├── lexical/                  # In-memory BM25 index
        │       ├── parentchild/              # Parent expansion and multi-vector indexing
        │       ├── rerank/                   # Candidate reordering strategies
        │       └── transform/                # Query transformation and multi-hop planning
        └── resources/
            └── application.yml               # Defaults and environment-variable overrides

Prerequisites

Required

Dependency Required version Purpose
Java Development Kit 21 Builds and runs the Spring Boot application
Maven 3.9+ Resolves dependencies, tests, packaging
Docker Engine / Docker Desktop Current version with Compose v2 Runs Qdrant and Kafka locally
Ollama Current version Runs the default chat and embedding models
Available disk memory At least 8 GB recommended Stores Docker images, models, vectors, and PDFs

The application has been configured for Java 21. Java 17 or older is not supported by the Maven configuration.

Install prerequisites

  • macOS: install a JDK such as Temurin 21, Maven, Docker Desktop, and Ollama.
  • Windows: install JDK 21, Maven, Docker Desktop with the WSL 2 backend enabled, and Ollama for Windows. Use PowerShell, Windows Terminal, Git Bash, or WSL for the commands below.
  • Linux: install OpenJDK 21, Maven, Docker Engine plus Docker Compose v2, and Ollama. Ensure your user can run docker without sudo, or use sudo consistently.

Confirm installations before proceeding:

java -version
mvn -version
docker --version
docker compose version
ollama --version

If docker: command not found appears, Docker Desktop/Engine is not installed or is not available in the current terminal session. Install it, start the Docker application/service, then open a new terminal.

Run on any supported system

1. Get the source

Clone the repository or copy the complete ADVANCE-RAG directory to the target machine. Then open a terminal in the project root:

cd /path/to/ADVANCE-RAG

Windows PowerShell example:

cd C:\path\to\ADVANCE-RAG

2. Start the required infrastructure

The default Compose stack starts Qdrant and Kafka:

docker compose up -d
docker compose ps

Expected services and host ports:

Service Host port Purpose
Qdrant HTTP 6333 Qdrant dashboard/API
Qdrant gRPC 6334 Spring AI vector-store connection
Kafka 9092 Asynchronous ingestion events

You can inspect container output if startup fails:

docker compose logs qdrant
docker compose logs kafka

3. Download the default Ollama models

Start Ollama if your operating system does not start it automatically, then download the configured chat and embedding models:

ollama pull llama3.2
ollama pull nomic-embed-text

The defaults can be changed with environment variables described in Configuration. The embedding model must remain available while the application is running, because it is used at ingestion and query time.

4. Build and test

mvn clean test

This downloads Maven dependencies on the first run. A successful test/build is the best first check that JDK 21 and Maven are configured correctly.

5. Start the application

For development:

mvn spring-boot:run

For a packaged JAR:

mvn clean package
java -jar target/advance-rag-0.0.1-SNAPSHOT.jar

The HTTP service listens on http://localhost:8080 by default.

6. Verify health and active selection

curl http://localhost:8080/actuator/health
curl http://localhost:8080/api/providers/active

Expected provider response with default configuration:

{
  "vectorDatabase": "qdrant",
  "llm": "ollama"
}

Stop the local stack

Stop containers while retaining Qdrant and Kafka data:

docker compose down

To delete container volumes and all indexed local infrastructure data, use the following destructive command only when you intentionally want a clean environment:

docker compose down -v

The locally staged PDFs are stored under data/uploads by default and are not removed by docker compose down.

Configuration

All default settings are in src/main/resources/application.yml. Spring Boot permits values to be overridden with environment variables, command-line flags, or a deployment-specific configuration file.

Infrastructure and models

Configuration property Environment variable Default Description
spring.ai.ollama.base-url OLLAMA_BASE_URL http://localhost:11434 Ollama server URL
spring.ai.ollama.chat.options.model OLLAMA_CHAT_MODEL llama3.2 Answering, transformation, and LLM-reranking model
spring.ai.ollama.embedding.options.model OLLAMA_EMBEDDING_MODEL nomic-embed-text Dense embedding model
spring.ai.vectorstore.qdrant.host QDRANT_HOST localhost Qdrant host
spring.ai.vectorstore.qdrant.port QDRANT_PORT 6334 Qdrant gRPC port
spring.kafka.bootstrap-servers KAFKA_BOOTSTRAP_SERVERS localhost:9092 Kafka broker
rag.ingestion.storage-path RAG_INGESTION_STORAGE_PATH ./data/uploads Local PDF staging directory

Example for a remote Ollama and Qdrant installation:

export OLLAMA_BASE_URL=http://ollama.internal:11434
export QDRANT_HOST=qdrant.internal
export QDRANT_PORT=6334
mvn spring-boot:run

PowerShell equivalent:

$env:OLLAMA_BASE_URL = "http://ollama.internal:11434"
$env:QDRANT_HOST = "qdrant.internal"
$env:QDRANT_PORT = "6334"
mvn spring-boot:run

RAG strategy configuration

Most RAG strategies are JSON values to make a single configuration value portable across YAML, Docker, Kubernetes, and environment variables. Update application.yml for a shared default, or override the relevant value at deployment time.

rag:
  chunking:
    config: '{"strategy":"recursive","chunkSize":800,"chunkOverlap":120,"sentenceWindow":2,"semanticSimilarityThreshold":0.72,"tableRowsPerChunk":40}'
  hybrid-search:
    config: '{"fusion":"rrf","candidateCount":8,"rrfK":60,"denseWeight":0.6,"keywordWeight":0.4}'
  query-transformation:
    config: '{"enabled":true,"techniques":["rewrite","expansion","multi-query"],"maxQueries":6}'
  reranking:
    config: '{"strategy":"hybrid","topK":5,"biEncoderWeight":0.35,"keywordWeight":0.25,"crossEncoderWeight":0.40}'
  context-compression:
    config: '{"strategy":"hybrid","maxSentencesPerDocument":4,"maxCharacters":6000}'
  multi-hop:
    config: '{"enabled":true,"maxHops":1}'

These settings are read at request time; restart the application after changing a YAML file to ensure Spring loads the new file.

API reference

All APIs are rooted at http://localhost:8080.

Upload a PDF for asynchronous ingestion

POST /api/rag/documents

Content type: multipart/form-data

Field Required Description
file Yes A non-empty .pdf file; maximum upload size is 25 MB by default
metadata No JSON string describing filtering, ownership, and citation data

Example:

curl -X POST http://localhost:8080/api/rag/documents \
  -F "file=@/absolute/path/to/travel-policy.pdf" \
  -F 'metadata={"title":"India Travel Policy","department":"Finance","country":"India","publishedDate":"2025-04-01","source":"SharePoint","documentType":"Policy","owner":"finance-team","confidentiality":"internal","visibility":"internal","tags":["policy","travel"],"allowedUsers":["finance-analyst"]}'

Successful submission returns 202 Accepted:

{
  "job": {
    "jobId": "7d2c...",
    "documentId": "a SHA-256 hash",
    "status": "QUEUED",
    "chunks": null,
    "error": null
  }
}

Check ingestion status

GET /api/rag/documents/jobs/{jobId}

curl http://localhost:8080/api/rag/documents/jobs/<jobId>

Statuses are QUEUED, PROCESSING, COMPLETED, or FAILED. COMPLETED includes the number of indexed chunk and multi-vector representations.

Ask a question

POST /api/rag/query

curl -X POST http://localhost:8080/api/rag/query \
  -H "Content-Type: application/json" \
  -d '{
    "question":"What does the travel policy say about eligible expenses?",
    "filters":{
      "department":"Finance",
      "country":"India",
      "publishedAfter":"2025-01-01",
      "tags":["policy"],
      "userId":"finance-analyst"
    }
  }'

Supported filter properties are department, country, source, documentType, publishedAfter, publishedBefore, tags, and userId. Omit filters to search publicly visible documents. The response contains answer and citation entries with title, source, page number where available, and parent-section ID.

Inspect configured provider selection

GET /api/providers/active

curl http://localhost:8080/api/providers/active

Metrics and health

curl http://localhost:8080/actuator/health
curl http://localhost:8080/actuator/metrics

Spring Boot Actuator exposes health, info, and metrics only. The RAG query path records query timing and failures through Micrometer.

Chunking strategies

Set rag.chunking.config.strategy to one of the following values.

Strategy Best suited for Behaviour
default General PDFs Delegates to recursive chunking
fixed-size Predictable-size text Character windows with overlap
sliding-window Boundary-sensitive QA Overlapping fixed windows
recursive General prose and mixed PDF text Splits on paragraphs, lines, sentences, then words
paragraph Well-structured prose Keeps paragraphs together where possible
sentence-window Narrative or FAQ content Groups overlapping sentences
hierarchical Documents where broad context matters Produces linked parent/child structure
semantic Topic-changing prose Uses sentence embeddings and a similarity threshold
markdown-aware Markdown-like documentation Preserves headings with their sections
table-aware Tabular extraction Retains table blocks and repeats headers across row groups
code-aware Source-code-like documentation Groups common declarations; not a language AST parser

Example semantic configuration:

rag:
  chunking:
    config: '{"strategy":"semantic","chunkSize":800,"chunkOverlap":120,"sentenceWindow":2,"semanticSimilarityThreshold":0.72,"tableRowsPerChunk":40}'

Semantic chunking requires the Ollama embedding model and will make ingestion slower than deterministic strategies.

Retrieval quality features

Metadata filtering and visibility

Metadata is copied from the upload to every parent, chunk, and multi-vector representation. Qdrant and BM25 both apply the same department, country, source, type, date, tag, and visibility constraints before results are fused. A document is public when visibility is public; non-public documents require a matching userId in allowedUsers.

The supplied userId is a request attribute, not an authenticated identity. Put this service behind authentication and derive the identity/permissions on the server before using it for production access control.

Hybrid search

Each indexed representation goes to Qdrant for semantic retrieval and BM25 for exact lexical retrieval. The results are merged with either:

  • rrf: Reciprocal Rank Fusion; recommended default and robust when score scales differ.
  • weighted: linearly weighted rank contributions using denseWeight and keywordWeight.

The BM25 index is in memory. Re-ingest documents after an application restart, or replace it with a durable lexical search system for production.

Query transformation

Supported techniques are rewrite, expansion, multi-query, hyde, step-back, and decomposition. Each uses the configured chat model. More techniques can improve recall but also add local-model calls and latency. Start with rewrite and multi-query for a practical balance.

Reranking

Strategy Behaviour Cost
bi-encoder Keeps hybrid retrieval order Lowest
bm25 / keyword Reorders by query term overlap Low
cross-encoder / llm-cross-encoder Uses the chat model to score each question-document pair High
hybrid Combines original rank, keyword score, and LLM score Highest

Context compression

extract, summarize, and hybrid use the chat model. sentence-selection, compression-retriever, and token-pruning provide deterministic alternatives. maxCharacters is a final hard guard on the prompt context sent to the answering model.

Parent-child, multi-vector, and multi-hop retrieval

PDF pages are retained as parent documents; searchable chunks point to a parentId. Matching children are expanded back to their parent before reranking, which restores surrounding context. Title, summary, and frequency-based keyword representations are indexed as additional retrieval routes. Multi-hop retrieval can create one follow-up question from first-hop evidence and merge its results.

Provider options

The provider gateway validates configured provider names and reports the selected values:

rag:
  providers:
    config: '{"vectorDatabase":"qdrant","llm":"ollama"}'

Recognised vector database names: qdrant, chroma, milvus.

Recognised LLM names: ollama, localai, vllm.

Optional provider containers can be started with:

docker compose --profile providers up -d
Optional service Port Notes
Chroma 8000 Vector database container
Milvus 19530 Starts with required etcd and MinIO dependencies
MinIO console 9001 Milvus object-storage console; default credentials are in compose.yaml
LocalAI 8080 Requires models to be installed/configured inside its mounted model directory
vLLM 8001 Requires suitable GPU/container runtime in real deployments

Important: the current live Spring AI retrieval and generation path is wired to Qdrant and Ollama. Chroma, Milvus, LocalAI, and vLLM connection classes and Docker services are available for provider configuration and health/selection groundwork, but they are not yet full runtime adapter replacements. Do not change the provider JSON expecting the active retrieval pipeline to automatically switch to those services without implementing their Spring AI adapters.

Operations, verification, and troubleshooting

Common checks

# Application logs when started through Maven
mvn spring-boot:run

# Container health and logs
docker compose ps
docker compose logs --tail=100 qdrant
docker compose logs --tail=100 kafka

# Confirm models installed in Ollama
ollama list

# Confirm Qdrant answers on its HTTP port
curl http://localhost:6333/collections

Problem: Docker command is unavailable

Install Docker Desktop on macOS/Windows or Docker Engine plus Compose v2 on Linux. Start it and open a new terminal. Confirm with docker compose version.

Problem: application cannot connect to Ollama

Ensure Ollama is running, then run ollama list and verify both configured model names exist. For a remote host, set OLLAMA_BASE_URL to a reachable URL. If Ollama runs in a container, localhost from the application container is not the host; use the appropriate Docker service hostname/network configuration.

Problem: application cannot connect to Qdrant

Run docker compose ps, verify Qdrant is running, and use gRPC port 6334 for QDRANT_PORT. Port 6333 is the Qdrant HTTP/API port, not the configured Spring AI gRPC port.

Problem: ingestion remains QUEUED

Kafka may not have started or the application cannot reach it. Check docker compose logs kafka, confirm KAFKA_BOOTSTRAP_SERVERS is correct, and review application logs. A FAILED job includes the captured processing error in its status response.

Problem: answers have no useful context after restart

Qdrant persists its Docker volume, but the current BM25 and parent-document stores live only in application memory. Re-ingest PDFs after a service restart, or implement durable storage/rebuild logic before relying on restart continuity.

Problem: port 8080 is already in use

Either stop the conflicting service or start ADVANCE-RAG on another port:

mvn spring-boot:run -Dspring-boot.run.arguments="--server.port=8081"

Security and production guidance

This project is a local/reference RAG application, not a hardened production deployment. Before exposing it beyond a trusted environment:

  • Add authentication and authorization; do not trust caller-supplied userId values.
  • Store ingestion jobs, parent documents, and lexical indexes in durable shared storage.
  • Place Qdrant, Kafka, and model endpoints on private networks and require authentication/TLS.
  • Validate PDF type/content more deeply, scan uploads, and impose per-user quotas.
  • Replace default MinIO credentials and avoid committing secrets to source control.
  • Add Kafka retry topics, dead-letter handling, idempotent persistence, and distributed locking.
  • Add request rate limits, audit logging, tracing, backups, retention rules, and alerting.
  • Benchmark chunking, retrieval, reranking, and prompts using a labelled evaluation set before choosing defaults.

Useful commands

# Compile without running tests
mvn compile

# Run tests
mvn test

# Build runnable JAR
mvn clean package

# Start only default infrastructure
docker compose up -d

# Start default and optional provider containers
docker compose --profile providers up -d

# Stop containers, retain volumes
docker compose down

License

No license file is currently included. Add an explicit license before distributing or publishing the project.

About

ADVANCE-RAG is a configurable Spring Boot RAG platform for asynchronous PDF ingestion, advanced chunking, hybrid retrieval, metadata filtering, reranking, context compression, and local LLM/vector database integrations.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages