A Spring Boot application that provides a REST API for searching educational courses using Elasticsearch.
This application allows users to search for educational courses with various filtering options:
- Full-text search on course title and description
- Filter by category and type
- Filter by age range (minAge/maxAge)
- Filter by price range (minPrice/maxPrice)
- Filter by session date (courses starting on or after a given date)
- Sort by upcoming session date or price (ascending/descending)
- Pagination support
- Java 17 or higher
- Maven 3.6 or higher
- Elasticsearch 7.x or 8.x running on localhost:9200
git clone <repository-url>
cd course-search-api
Make sure Docker is installed and running.
In your project folder (where docker-compose.yml
is), run:
docker-compose up -d
This starts Elasticsearch on http://localhost:9200
.
To check if it’s running, open a terminal and run:
curl http://localhost:9200
mvn clean install
mvn spring:run
Or run the JAR file directly:
java -jar target/course-search-api-0.0.1-SNAPSHOT.jar
The application will start on port 8080 by default.
The application is configured to connect to Elasticsearch at http://localhost:9200. This configuration is defined in src/main/resources/application.yml
:
spring:
elasticsearch:
uris: http://localhost:9200
connection-timeout: 5s
socket-timeout: 10s
If you need to connect to Elasticsearch at a different location, modify these properties accordingly.
The application uses the following data model for courses:
Field | Type | Description |
---|---|---|
id | String | Unique identifier for the course |
title | Text | Course title (used for full-text search) |
description | Text | Course description (used for full-text search) |
category | Keyword | Course category (used for exact filtering) |
type | Keyword | Course type (used for exact filtering) |
gradeRange | Keyword | Grade range for the course |
minAge | Integer | Minimum age requirement |
maxAge | Integer | Maximum age limit |
price | Double | Course price |
nextSessionDate | Date | Date of the next available session |
The application automatically loads sample course data from src/main/resources/sample-courses.json
when it starts up. This is handled by the CourseIndexer
component, which:
- Reads the JSON file from the resources folder
- Deserializes the data into
CourseDocument
objects - Bulk-indexes the documents into the Elasticsearch "courses" index
You can verify the data ingestion by:
- Checking the application logs for a success message: "✅ Successfully indexed X courses to Elasticsearch."
- Querying the Elasticsearch index directly:
curl -X GET "http://localhost:9200/courses/_count"
GET /api/search
Parameter | Type | Required | Description |
---|---|---|---|
q | String | No | Search keyword for title and description |
category | String | No | Filter by exact category match |
type | String | No | Filter by exact type match |
minAge | Integer | No | Filter courses with minAge >= specified value |
maxAge | Integer | No | Filter courses with maxAge <= specified value |
minPrice | Double | No | Filter courses with price >= specified value |
maxPrice | Double | No | Filter courses with price <= specified value |
startDate | String | No | ISO-8601 date to filter courses starting on/after this date |
sort | String | No | Sort order: "upcoming" (default), "priceAsc", "priceDesc" |
page | Integer | No | Page number (0-based, default: 0) |
size | Integer | No | Page size (default: 10) |
{
"total": 42,
"courses": [
{
"id": "course123",
"title": "Introduction to Programming",
"description": "Learn the basics of programming...",
"category": "Computer Science",
"type": "Online",
"gradeRange": "9-12",
"minAge": 14,
"maxAge": 18,
"price": 199.99,
"nextSessionDate": "2025-08-15T09:00:00Z"
},
{
"id": "course456",
"title": "Advanced Data Science",
"description": "Explore machine learning algorithms...",
"category": "Data Science",
"type": "Hybrid",
"gradeRange": "College",
"minAge": 18,
"maxAge": 99,
"price": 499.99,
"nextSessionDate": "2025-09-01T18:30:00Z"
}
]
}
Search for courses containing "math" in title or description:
curl -X GET "http://localhost:8080/api/search?q=math"
Search for online math courses for ages 10-12 with price under $100:
curl -X GET "http://localhost:8080/api/search?q=math&type=Online&minAge=10&maxAge=12&maxPrice=100"
Get all science courses sorted by price (low to high):
curl -X GET "http://localhost:8080/api/search?category=Science&sort=priceAsc"
Get courses starting after July 20, 2025, page 2 with 5 results per page:
curl -X GET "http://localhost:8080/api/search?startDate=2025-07-20T00:00:00Z&page=1&size=5"
Search for art courses for teenagers (13-19) starting in August 2025 or later, sorted by price (high to low):
curl -X GET "http://localhost:8080/api/search?category=Art&minAge=13&maxAge=19&startDate=2025-08-01T00:00:00Z&sort=priceDesc"
- Full-text search: Searching for keywords should match courses with those terms in title or description, with fuzzy matching for typos.
- Filtering:
- Category and type filters should match exactly
- Age range filters should return courses where the specified age falls within the course's min-max age range
- Price filters should return courses within the specified price range
- Date filter should return only courses with sessions on or after the specified date
- Sorting:
- Default sort should show upcoming courses first (earliest nextSessionDate)
- priceAsc should sort from lowest to highest price
- priceDesc should sort from highest to lowest price
- Pagination:
- page and size parameters should limit results appropriately
- total count should reflect the total number of matching courses, not just the current page
- Start the application and verify data ingestion in logs
- Try various search combinations using the example curl commands
- Verify that results match the expected behavior for each filter and sort option
- Check pagination by comparing total count with returned results and trying different page numbers
- CourseDocument: Entity class mapping to Elasticsearch documents
- CourseRepository: Spring Data repository for basic CRUD operations
- CourseIndexer: Component that loads and indexes sample data
- CourseSearchService: Service implementing the search functionality
- CourseSearchController: REST controller exposing the search API