perf(search+embed): zero-copy embedding API and deferred RRF mapping

Change OllamaClient::embed_batch to accept &[&str] instead of
Vec<String>. The EmbedRequest struct now borrows both model name and
input texts, eliminating per-batch cloning of chunk text (up to 32KB
per chunk x 32 chunks per batch). Serialization output is identical
since serde serializes &str and String to the same JSON.

In hybrid search, defer the RrfResult->HybridResult mapping until
after filter+take, so only `limit` items (typically 20) are
constructed instead of up to 1,500 at RECALL_CAP. Also switch
filtered_ids to into_iter() to avoid an extra .copied() pass.

Switch FTS search_fts from prepare() to prepare_cached() for statement
reuse across repeated searches. Benchmarked at ~1.6x faster.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Taylor Eernisse
2026-02-05 17:35:53 -05:00
parent 16beb35a69
commit 3e9cf2358e
4 changed files with 30 additions and 31 deletions

View File

@@ -67,7 +67,7 @@ pub fn search_fts(
LIMIT ?2
"#;
let mut stmt = conn.prepare(sql)?;
let mut stmt = conn.prepare_cached(sql)?;
let results = stmt
.query_map(rusqlite::params![fts_query, limit as i64], |row| {
Ok(FtsResult {