Skip to content

How search works

Moonjar searches your library three ways. By default it picks the right one for the query you typed; you can also force a specific mode.

Moonjar tries full-text first. If that returns no results, it falls back to semantic search. This combination handles most queries — exact strings hit full-text, vague recall falls through to semantic.

A Postgres tsvector index over the source text of every document. Tokenises words, stems them, and ranks results with ts_rank. Returns highlighted snippets so you can see why a result matched.

Best for:

  • Unique strings (booking references, postcodes, IDs).
  • Quoted phrases.
  • Anything where the exact word matters.

A vector index over an embedding of every document. Queries get embedded the same way and results are ranked by cosine similarity — closer in meaning ranks higher.

Best for:

  • Vague recall — “that thing about retirement plans”.
  • Cross-language matches.
  • Concepts that don’t share words with the document.

A direct lookup against the extracted fields on every document. Matches against a field name (vendor, total, provider) or a value substring.

Best for:

  • “all my Vodafone bills” (vendor = Vodafone).
  • Lookups by exact field value.

Documents and their extracted fields. The command palette extends this across memories, reminders, collection items, and conversations — five entity types in one ranked result list.

Group-shared items are searched alongside your own.

  • Auto-mode falls back from full-text to semantic when full-text returns nothing — so a query that matches one document by an obscure word will still surface that document.
  • Search is per-account. You don’t see other users’ documents unless they’re shared with you through a group.
  • Search inside attachments depends on whether the attachment text was extracted at capture (PDFs and images: yes; raw binaries: no).