Antfly

Distributed search engine: BM25 full-text, vector, and graph search in one service.

Goals

A single search backend for three distinct retrieval patterns: BM25 keyword search over the diary (SQI pattern), semantic vector search over GitHub stars, and full-text search over the benchristel wiki. We wanted one service rather than Elasticsearch + a vector DB + a separate BM25 index.

Effectiveness

Effective for everything we've actually used. BM25 search over the diary and wiki works well. The SQI pattern — indexing synthetic queries per chunk rather than the chunks themselves — significantly improves recall on short, context-dependent diary entries. Vector search on GitHub stars works but hasn't been load-tested.

What made it effective

Bonus utility

Graph search is available but unused. Once the diary and wiki have relationship edges, traversal-based retrieval (e.g. "what tasks relate to this concept?") is possible without adding another service.

Friction / pain points / surprises

/api/v1/search returns HTML, not search results. The URL looks like it should be the query endpoint. It's the dashboard. Use /api/v1/query. This has bitten us more than once.

benchristel-wiki has no embeddings index. HyDE search against the wiki falls back to extracting key terms from the hypothetical document and running BM25. Semantic search on the wiki requires re-indexing with an embeddings index — not done yet, so recall depends entirely on keyword overlap.

Response shape is nested. { "responses": [{ "hits": { "hits": [...] } }] } — two levels of wrapping before you reach the actual hits. Every consumer needs the same unwrap boilerplate.