Search & Ranking
Implementation: internal/search/search.go. Two phases: hard-filter, then fuzzy score.
MatchesDoc — hard filters (bare words ignored)
Section titled “MatchesDoc — hard filters (bare words ignored)”Tags: subset, case-insensitive.NotTags: exclusion.DocType: exact, case-folded.Title/ generickey:value:fuzzyContainsFold= case-insensitive substring orsahilm/fuzzyhit.Status: exact-fold, plusstatus:archivedmatchesIsArchived().Path: substring-fold.- Dates:
Created/UpdatedviamatchDate(inclusive/exclusiveFrom/To);date/before/afteruse either-semantics (matchEither). Nil timestamp never matches a present filter.
Rank — bare-word scoring
Section titled “Rank — bare-word scoring”- Filter via
MatchesDoc. - No bare words → sort by
Path. - Else
scoreDocper doc: every bare word must match — AND semantics, miss drops the doc. A word matches by case-insensitive substring ofSearchBlob(fallbackTitle+" "+Body); only if that misses does it fall back tosahilm/fuzzyagainst theTitle. - Sort: score desc → most-recent
UpdatedAt(nil = oldest) →Path.
Score formula
Section titled “Score formula”Per bare word, scoreDoc adds a base plus a graded title boost:
| Contribution | Constant | Value | When |
|---|---|---|---|
| Match length | — | len(word) | word is a substring of the blob (body/frontmatter) |
| Fuzzy score | — | fuzzy.Find score | not in blob, but fuzzy-matches the title |
| Exact title | exactTitleBoost | +200 | title equals the word exactly |
| Whole-word title | titleBoost | +100 | word appears as a whole word in the title |
| Partial title | partialTitleBoost | +50 | word appears inside a longer title word |
The three title boosts are mutually exclusive, so whole-word/word-boundary hits are preferred over longer words that merely contain the query. A search for butter therefore ranks Butter (200 + 6) above Buttermilk (50 + 6), which in turn edges out a body-only mention (6). Boundaries are UTF-8-aware and treat any non-letter/digit/_ character (spaces, hyphens, punctuation) as a separator.
FilterArchived
Section titled “FilterArchived”Rank never hides; FilterArchived(docs, include) / TUI ctrl+a layer applies hiding. archived:true / status:archived still match hidden docs.
See also: Query Syntax for token semantics, and Backend Evaluation for the indexed-alternative decision.