A semantic search service for the Animal Kingdom, powered by PostgreSQL + pgvector.
IndexForge Search serves natural-language similarity queries over animal documents. It converts user queries into embedding vectors and finds the most relevant animals using cosine similarity search.
βββββββββββββββββββββββββββββββββββ
β User Query β
β "fast predators in Africa" β
ββββββββββββββββββ¬βββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β Query Embedding β
β Convert text β vector (1536d) β
ββββββββββββββββββ¬βββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β Vector Similarity Search β
β pgvector cosine distance (<=>)β
ββββββββββββββββββ¬βββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β Rank Results β
β Order by similarity score β
ββββββββββββββββββ¬βββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β Return Animal Documents β
β { name, description, score } β
βββββββββββββββββββββββββββββββββββ
- β Serves semantic search requests over animal documents
- β Reads animal data from PostgreSQL (pgvector)
- β Returns ranked results with similarity scores
- β Provides animal CRUD read endpoints
- β Read CSV files or ingest data
- β Call Wikipedia or any external data source
- β Perform data ingestion or ETL
- β Generate embeddings for documents (handled externally)
PostgreSQL is the only source of truth.
| Component | Technology |
|---|---|
| Language | Java 21 |
| Framework | Spring Boot 3.3 |
| Database | PostgreSQL 16 |
| Vector Store | pgvector |
| Migrations | Flyway |
| Build Tool | Maven |
| Code Gen | Lombok |
| Container | Docker Compose |
src/main/java/com/indexforge/search/
βββ IndexForgeSearchApplication.java # Entry point
βββ controller/
β βββ AnimalController.java # GET /api/v1/animals, GET /api/v1/animals/{id}
β βββ SearchController.java # GET /api/v1/search?q=
βββ dto/
β βββ AnimalResponse.java # Full animal details
β βββ SearchResultResponse.java # Search hit (id, name, description, score)
βββ entity/
β βββ Animal.java # JPA entity with pgvector column
βββ repository/
β βββ AnimalRepository.java # JPA + native pgvector queries
βββ service/
β βββ AnimalService.java # Read-only animal operations
βββ search/
β βββ SemanticSearchService.java # Orchestrates vector search
β βββ QueryEmbeddingService.java # Converts query β embedding vector
βββ config/
β βββ AppConfig.java # Spring beans configuration
βββ exception/
βββ AnimalNotFoundException.java
βββ GlobalExceptionHandler.java
CREATE TABLE animals (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
height VARCHAR(100),
weight VARCHAR(100),
color VARCHAR(255),
lifespan VARCHAR(100),
diet VARCHAR(255),
habitat TEXT,
predators TEXT,
average_speed VARCHAR(100),
countries_found TEXT,
description TEXT,
wikipedia_summary TEXT,
search_document TEXT,
embedding_vector vector(1536),
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);| Name | Type | Column | Purpose |
|---|---|---|---|
idx_animals_name |
B-tree | name |
Fast name lookups |
idx_animals_diet |
B-tree | diet |
Filter by diet |
idx_animals_habitat |
GIN | habitat |
Full-text search |
idx_animals_created_at |
B-tree | created_at |
Time-based sorting |
| (future) | HNSW | embedding_vector |
ANN vector search |
GET /api/v1/animals
Response: 200 OK
[
{
"id": 1,
"name": "Cheetah",
"height": "70-90 cm",
"weight": "21-72 kg",
"color": "Tan with black spots",
"lifespan": "10-12 years",
"diet": "Carnivore",
"habitat": "African savanna",
"predators": "Lions, Hyenas",
"averageSpeed": "112 km/h",
"countriesFound": "Kenya, Tanzania, Namibia",
"description": "The cheetah is the fastest land animal...",
"wikipediaSummary": "...",
"createdAt": "2026-06-13T12:00:00"
}
]GET /api/v1/animals/{id}
Response: 200 OK β Same format as above (single object)
Error: 404 Not Found
{
"timestamp": "2026-06-13T12:00:00",
"status": 404,
"error": "Not Found",
"message": "Animal not found with id: 99"
}GET /api/v1/search?q=fast animals that hunt in packs
Response: 200 OK
[
{
"animalId": 42,
"animalName": "African Wild Dog",
"description": "The African wild dog is a highly social predator...",
"similarityScore": 0.91
},
{
"animalId": 7,
"animalName": "Cheetah",
"description": "The cheetah is the fastest land animal...",
"similarityScore": 0.87
}
]- Java 21
- Docker & Docker Compose
- Maven
n
# 1. Start PostgreSQL with pgvector
docker-compose up -d
# 2. Build the project
mvn clean install -DskipTests
# 3. Run the application
mvn spring-boot:runThe service starts on http://localhost:8080.
# Health check
curl http://localhost:8080/api/v1/animals
# Search (returns empty until implementation is complete)
curl "http://localhost:8080/api/v1/search?q=large%20herbivores"| Component | Status |
|---|---|
| Animal entity + migration | β Done |
| Animal read endpoints | β Done |
| Search endpoint (skeleton) | β Done |
| QueryEmbeddingService | π² TODO |
| SemanticSearchService logic | π² TODO |
| HNSW vector index | π² TODO |
| Result pagination | π² TODO |
| Similarity threshold | π² TODO |
- Read-only β This service only reads from PostgreSQL. Data population happens externally.
- Constructor injection β All dependencies injected via
@RequiredArgsConstructor. - Clean layering β Controller β Service β Repository. No business logic in controllers.
- DTO separation β API responses decoupled from JPA entities.
- Fail-fast β Unimplemented features throw
UnsupportedOperationExceptionwith clear messages. - Database-first β Schema managed by Flyway migrations.
MIT