Semantic Search
When you save a note, Engram doesn’t just store the text. It also generates a vector embedding (a high-dimensional numeric representation of the note’s meaning) and indexes that vector in Qdrant. Search later compares your query vector against the indexed ones to find semantically related notes.
The pipeline
Section titled “The pipeline”note save → chunk → embed → Qdrant index ↑ Voyage AI (cloud) or Ollama (self-host)- Chunking. Long notes are split at heading boundaries first, then large sections are word-split. Chunk size is ~2048 characters (≈512 tokens at 4 chars/token). No overlap. The chunker relies on heading hierarchy and contextualization (prepending folder/heading path to each chunk) to preserve surrounding meaning rather than text overlap.
- Embedding. Each chunk goes to the embedding provider, which
returns a vector (1024-dim with Voyage’s
voyage-4-large). - Indexing. Vectors land in Qdrant with binary quantization for memory efficiency. Original full-precision vectors are kept for rescore.
- Asynchronous. The embed/index step runs via Oban (background job queue). The note is saved immediately; embedding catches up within seconds.
At query time
Section titled “At query time”- Embed the query with the same provider (using a different model for queries, which gives asymmetric retrieval and tighter accuracy)
- Vector search in Qdrant. Fast, binary-quantized similarity
- Rescore the top candidates against full-precision vectors
- Rerank (optional). When
RERANKER_BACKEND=jina+JINA_URLare configured, candidates are reordered via the Jina cross-encoder adapter (blends 40% vector + 60% reranker scores). Default is no reranker; raw vector ranking is returned. - Return top-K hits with highlighted excerpts
Why this works for vaults
Section titled “Why this works for vaults”Semantic search excels when your query and the relevant notes share meaning but not necessarily words. Examples:
- Query: “what did I write about onboarding new hires” → finds notes titled “Team intake process” even though they don’t contain “onboarding”
- Query: “why we picked Postgres over Mongo” → finds an old decision log titled “Database choice, DD-2024-03”
Keyword and hybrid search
Section titled “Keyword and hybrid search”Semantic isn’t the only mode. The backend also runs encryption-safe keyword search and a hybrid mode that fuses lexical and vector results server-side via reciprocal-rank fusion:
Engram supports keyword (lexical) search over your whole vault, and
it does so without breaking encryption at rest. Rather than scanning
plaintext, the backend indexes a per-chunk sparse vector keyed by
HMAC(your vault key, token), so the server can match query terms
against the index without ever holding readable note text. Keyword,
semantic (vector), and hybrid (lexical + vector fused server-side
via reciprocal-rank fusion) modes are all live in the backend.
This means true substring/regex search over raw text still isn’t
possible server-side (the index is over tokens, not characters), so for
regex, case-sensitive, or path-filtered literal search, Obsidian’s local
Search pane (running over your on-disk .md files) remains the tool. The
editor’s Ctrl/Cmd+F also works for find-within-an-open-note.
What you can do to improve search
Section titled “What you can do to improve search”- Write headings. Chunking respects heading boundaries; clean hierarchy = better chunks
- Use frontmatter for tags and metadata. Tags appear in embeddings and as filterable facets
- Don’t paste massive code blocks. Code embeds poorly. Link to it from a markdown note instead