Making Search Instant and Forgiving

One of the biggest challenges is handling large local music libraries efficiently. Searching through thousands (or tens of thousands) of tracks, albums, and artists needs to be fast, accurate, and forgiving.

Recently, I leveled up the search experience dramatically by introducing regex-based prefix matching using Tantivy's RegexQuery.

Let's dive into what changed, why it matters, and how it works under the hood.

The Problem with Basic Search

Before this update, search relied on Tantivy's standard term or phrase queries. It was decent, but:

Partial matches weren't always prefix-friendly.

Case sensitivity could trip users up.

No easy way to do "starts with" across multiple fields without complex query parsing

For a music player, search should feel instant and smart—like typing in Spotify or Apple Music, where partial, case-insensitive matches just work.

The Solution: RegexQuery for Prefix Matching

I added a flexible regex layer that transforms the user's query into a case-insensitive prefix pattern: (?i)query.*

Here's the core snippet:

let mut results: Vec<(f32, TantivyDocument)> = vec![];
let pattern = format!("(?i){}.*", regex::escape(query_string));
for field in fields {
let query = RegexQuery::from_pattern(&pattern, field)?;
let regex_results: Vec<(f32, TantivyDocument)> = searcher
.search(&query, &TopDocs::with_limit(10))?
.into_iter()
.map(|(score, doc_address)| (score, searcher.doc(doc_address).unwrap()))
.collect();
results.extend(regex_results);
}

(?i) makes it case-insensitive.

regex::escape(query_string) safely escapes special chars.

.* allows matching the rest of the field (prefix + anything).

We run this across all relevant fields (configurable per type).

Results are collected, deduped/sorted by score, and returned.

This gives true prefix matching with forgiveness on case and exact spelling—type "dark" and get "The Dark Side of the Moon" instantly.

Bonus: Tantivy's regex engine is blazing fast for these patterns, so even on huge libraries, results feel instantaneous.

How the Indexing Works

Search is powered by dedicated Tantivy indexes for Tracks, Albums, and Artists.

Key fields are indexed as TEXT for full-text search, with STORED for quick retrieval.

For example, the Track schema indexes essentials like:

title, artist, album, album_artist, composer, genre

Default searchable fields prioritize the most common ones users query.

(Albums focus on title/artist/year; Artists on name/bio.)

This setup keeps indexes lean while covering 99% of search needs.

GitHub Repo: https://github.com/tsirysndr/rockbox-zig
Tangled Repo: https://tangled.org/tsiry-sandratraina.com/rockbox-zig