A local file search engine built for the Software Design 2026 course at TU Cluj-Napoca. It indexes a directory tree on your machine and searches inside your files, through a JavaFX GUI and a CLI, backed by SQLite FTS5.
Current version: 3.0.0 (Iteration 3). See CHANGELOG.md for the full history.
Indexing
- Producer-consumer pipeline: parallel reader threads for extraction, one dedicated writer thread, bounded queue for backpressure, batched commits
- Incremental indexing, only files whose
lastModifiedchanged are re-read - Live re-indexing via
FileWatcheron Java'sWatchService, applies creates, edits and deletes after the initial index - Symlink loop detection through canonical path resolution and a visited set
- Stale entry cleanup for deleted files
- Apache Tika parsing for PDF, DOCX and HTML, plus binary file safety
- Dominant colour extraction for images via pixel sampling
- Configurable ignore rules, editable in the UI
Search
- Full-text search on SQLite FTS5 with BM25 ranking
- Filename matches weighted 10x over content matches
PathScorer, a 0 to 10 query-independent relevance score computed at index time- Five ranking strategies: relevance, path score, date, size, alphabetical
- Query preprocessing decorator pipeline: sanitization, synonym expansion, automatic wildcards
- Boolean operators, wildcards and phrase search through native FTS5 syntax
- Qualifiers:
ext:,path:,name:,content:,color: - Search history with autocomplete suggestions and behaviour-based result boosting
Interface
- JavaFX GUI (MVVM) with live search, 350ms debounce, term highlighting, file preview and pagination
- Context-aware widget strip: gallery widget for image-heavy results, log analyzer for log-heavy results
- Search analytics dashboard with session and database statistics
- Interactive CLI with TEXT and JSON report export
| Layer | Technology |
|---|---|
| Language | Java 21 |
| Build | Maven |
| Database | SQLite + FTS5 (xerial/sqlite-jdbc 3.45.1.0) |
| Parsing | Apache Tika 2.9.1 |
| GUI | JavaFX 17.0.2 + AtlantaFX NordDark |
| Testing | JUnit 5.10.2, Mockito 5.11.0 |
| Formatting | Spotless + Google Java Format |
src/main/java/app/
├── Main.java — CLI composition root
├── cli/CLI.java — interactive CLI
├── config/IndexConfig.java — runtime configuration and ignore defaults
├── db/
│ ├── Database.java — connection, pragmas, schema, migrations
│ └── FileRepository.java — all SQL queries
├── gui/
│ ├── MainApp.java — JavaFX entry point
│ ├── SearchController.java — FXML controller
│ ├── SearchViewModel.java — search state
│ ├── IndexViewModel.java — indexing state and progress
│ ├── ResultCellFactory.java — custom result cells
│ ├── TextHighlighter.java — match highlighting in previews
│ └── widget/ — context-aware widget strip
│ ├── ContextWidget.java
│ ├── WidgetFactory.java
│ ├── GalleryWidget.java
│ └── LogAnalyzerWidget.java
├── indexer/
│ ├── FileIndexer.java — traversal, producer-consumer pipeline
│ ├── FileWatcher.java — live filesystem watching
│ ├── FileFilter.java — directory and extension filtering
│ ├── PathScorer.java — query-independent relevance score
│ └── IndexerFactory.java
├── model/ — FileRecord, SearchResult, IndexReport, TraversalStats
├── processor/
│ ├── ContentExtractor.java — strategy dispatch by MIME type
│ └── strategy/ — TextExtractionStrategy, ImageExtractionStrategy
├── search/
│ ├── SearchEngine.java — search subject, notifies observers
│ ├── SearchRequestParser.java — qualifier parsing
│ ├── RankingStrategy.java — ranking strategies
│ ├── SearchHistoryService.java — history observer, suggestions, boosting
│ ├── SearchObserver.java / SearchEvent.java
│ └── preprocessor/ — Sanitization, Synonym and Logic decorators
└── util/FileTypes.java — text and image extension registries
mvn javafx:run
- Enter or browse to a directory
- Click Index, progress is shown live in the status bar
- Type in the search bar, results appear as you type
- Filter by extension, path or dominant colour, or change the sort strategy
- Click a result to preview it, with matched terms highlighted
mvn compile exec:java -Dexec.mainClass="app.Main" -Dexec.args="D:\YourDirectory"
Arguments: <directory> [database] [TEXT|JSON]. Defaults are the user home directory, vision_index.db and TEXT.
| Syntax | Example | Description |
|---|---|---|
| keyword | main |
Full-text search, wildcard implied |
| phrase | "public static void" |
Exact phrase |
| boolean | index AND NOT test |
AND, OR, NOT |
| wildcard | index* |
Prefix match |
| extension | main ext:java ext:kt |
Filter by extension, OR semantics |
| path | config path:src |
Filter by path substring |
| name | name:Indexer |
Match filename only |
| content | content:bm25 |
Match file content only |
| colour | logo ext:png color:blue |
Filter images by dominant colour |
Queries pass through a decorator pipeline before reaching FTS5. Unqualified terms are sanitized, expanded through synonyms.properties, and given a trailing wildcard, so index also matches indexer and indexing.
Two independent signals decide result order.
BM25, from FTS5, scores query relevance. The name column is weighted 10x over content, so searching FileIndexer surfaces the file itself above the files that merely mention it.
PathScorer computes a 0 to 10 score per file at index time, independent of any query, stored in the files table and indexed with a B-tree. Source extensions weigh more than config and markup, paths under /src/main/ are boosted, vendor, generated and node_modules paths are penalised, and deeply nested paths decay slightly. It is a heuristic, and its purpose is to push your own code above everything vendored into your tree.
Results returned for queries you actually run gain a small persistent boost, capped so that history can nudge ranking without dominating it.
CREATE TABLE files (
path TEXT PRIMARY KEY,
name TEXT NOT NULL,
extension TEXT,
sizeBytes INTEGER NOT NULL,
lastModified INTEGER NOT NULL,
preview TEXT,
pathScore REAL NOT NULL DEFAULT 0.0,
dominantColor TEXT
);
CREATE VIRTUAL TABLE files_fts USING fts5(
path UNINDEXED,
name,
content
);B-tree indexes on extension, lastModified DESC, sizeBytes DESC, pathScore DESC and dominantColor. Schema changes are applied through guarded ALTER TABLE migrations, so existing databases upgrade in place.
Pragmas: journal_mode = WAL for concurrent CLI and GUI access, cache_size = -32000 for a 32MB page cache, synchronous = NORMAL.
Directories: .git, .idea, .hidden, node_modules, target, build, dist, cache, env, venv, AppData, flutter, scoop, __pycache__
Extensions: class, obj, o, pyc, pyo, zip, tar, gz, rar, 7z, tmp, bak, lnk, db, sqlite, lock, iml, suo, user, map, DS_Store
Everything else is indexed by metadata. Text files, documents parsed by Tika and images additionally get their content or dominant colour indexed.
mvn test
Unit tests cover the query decorator pipeline, the request parser, the path scorer, the search history service and content extraction. RankingIntegrationTest runs the full ranking path against an in-memory SQLite database.
See ARCHITECTURE.md for the full C4 model covering system context, containers, components and runtime sequence diagrams.
Design patterns in use: Strategy for ranking and extraction, Decorator for the query pipeline, Observer for search history, Factory for indexers and widgets, MVVM in the GUI.