> ## Documentation Index
> Fetch the complete documentation index at: https://docs.memloom.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Retrieval

> Hybrid recall: vector + keyword + entity, fused with reciprocal-rank fusion

## Why hybrid

Vector search alone misses exact identifiers (file name (e.g. `pg_hba.conf`), a ticket
number, or a specific concept) because embeddings blur precise strings into approximate meaning. Keyword search
alone misses the meaning, so memloom runs both (plus an entity arm) inside the database, in a
single SQL function (`memloom_fuse`), and fuses the rankings. There's no reranker service and
no second round trip: one query, one fused result list.

All arms rank saved memories **and** context chunks together in one pool, so "search my
memories" and "search my files" are the same operation.

## The three arms

| Arm         | Signal                                         | Catches                                                                           |
| ----------- | ---------------------------------------------- | --------------------------------------------------------------------------------- |
| **Vector**  | pgvector cosine distance over embeddings       | Meaning: paraphrases, translations, "the thing about restarting that worker"      |
| **Keyword** | Postgres full-text search                      | Exact words: file paths, error codes, config keys, names                          |
| **Entity**  | Query-to-entity similarity, then mention edges | Things: everything that *mentions* an entity the query names, however it's worded |

The entity arm has an **abstention gate**: it only fires when the query is clearly about a
known entity (query ↔ entity cosine ≥ 0.60). A vague query anchors to nothing and the arm
contributes nothing, so it never drags in unrelated results. The keyword arm abstains
the same way: no lexical match, no votes.

## Reciprocal-rank fusion

Each arm produces a ranking; fusion combines *ranks* rather than scores (cosine distances and FTS
ranks aren't comparable):

```
score(result) = Σ over arms:  weight_arm / (60 + rank_in_arm)
```

Default weights: vector **1.0**, keyword **2.0**, entity **0.5**. Keyword is up-weighted
because it abstains when it has nothing, so its votes are cheap and precise; the entity arm
is half-weighted so it works as a tiebreaker between arms rather than a winner on its own
(both eval-tuned on a real corpus). A result that two arms agree on beats a result that tops
one arm alone.

Each recall result carries both numbers:

* `rrfScore`: the fused rank score. **This is the order results arrive in.**
* `similarity`: the raw cosine signal alone, useful as a "how semantically close" query is to the result.

## What makes results good in practice

* **Exact identifiers are excellent queries.** The keyword arm makes `memloom recall
  "pg_hba.conf"` precise in a way pure-vector systems can't be.
* **Chunks embed their breadcrumb.** A markdown chunk is stored as
  `Guide > Setup > Postgres\n\n<text>`: the heading path is *prepended to the text*, so both
  the vector and the keyword arm see the heading context along with the paragraph.
* **Index your store.** The entity arm only works over what `memloom index` has processed.
  An unindexed store still recalls fine on the other two arms.
* **Stale never surfaces.** Every arm filters `status = 'active'`, so superseded versions of
  a belief can't shadow the current one.

<Note>
  In offline mode (no API key) the vector arm runs on deterministic hash embeddings, which makes texts
  sharing words score as similar, which is a real but low signal compared to cloud embedding. The keyword arm works at
  full quality offline; the entity arm needs indexing, which needs the LLM. For production
  recall quality, just configure a key [here](/guides/configuration).
</Note>
