# [Searchable]

> Mark a text field searchable. `[Searchable]` gives a String or Markdown property the best relevance search the app can offer — full-text always, semantic ranking when an embedder is configured. Scope picks entity-local field search vs the shared cross-entity corpus; mode picks lexical-only vs lexical+semantic.

<!-- id: memory-searchable · area: memory · stability: stable · html: https://osysharp.com/reference/memory/searchable/ -->

## Summary        {#summary}
`[Searchable]` marks a `String` or `Markdown` property as searchable. It gives the field the best relevance search
the app can offer: **full-text always works** (no setup), and **semantic ranking upgrades it** the moment an
embedding provider is configured — with no change to your code. Two optional arguments choose *where* the searchable
content lives (**scope**) and *which* kinds of relevance you get (**mode**). Requires `using Memory;`.

## Signature      {#signature}
```osy syntax
using Osysharp.Memory;

[Searchable]                      // scope defaults by type; Full
[Searchable(Entity)]              // entity-local field search; Full
[Searchable(Memory)]             // chunked into the shared corpus; Full
[Searchable(Entity, TextOnly)]   // entity-local; lexical only (no embedder needed)
```
Valid only on a `String` or `Markdown` property. Enums: `SearchScope { Entity, Memory }`,
`SearchMode { Full, TextOnly }`. Both arguments are optional and order-independent.

## Description    {#description}
A `[Searchable]` field participates in relevance search. What you get is governed by two orthogonal axes.

### Scope — where the searchable content lives   {#scope}
- **`Entity`** — the field is indexed **on its own row**, for *entity-local* field search. You query it with the
  field primitives `Prop.Matches(q)`, `Prop.TextScore(q)`, and `Prop.Similarity(q)` and compose your own ranking
  (see [field search (Matches / TextScore / Similarity)](https://osysharp.com/reference/memory/field-search/)). This is the default for a `String` property.
- **`Memory`** — the field's text is chunked into the app's **shared corpus**, the cross-entity store that
  [using Memory (semantic search)](https://osysharp.com/reference/memory/search/) searches with one turnkey call. This is the default for a `Markdown` property (Markdown is
  typically long and sectioned, so the corpus is its natural home).

If you don't write a scope, it's chosen by the property's type: **`String` → `Entity`**, **`Markdown` → `Memory`**.
Write the scope explicitly to override — e.g. `[Searchable(Memory)] string Summary;` puts a short String field into
the corpus, and `[Searchable(Entity)] Markdown Body;` keeps a Markdown field's search entity-local.

### Mode — which kinds of relevance   {#mode}
- **`Full`** *(default)* — both **lexical** (full-text keyword match) and **semantic** (meaning-based, vector)
  ranking. Semantic ranking is active whenever an embedding provider is configured; without one, the field still
  works as full-text and upgrades automatically once an embedder is wired.
- **`TextOnly`** — **lexical only.** No embedder is ever needed, and the field carries no per-row vector. Use it
  when keyword search is all you want and you don't want the storage or the dependency. `TextOnly` applies to
  `Entity` scope only — the shared corpus is always hybrid, so `[Searchable(Memory, TextOnly)]` is rejected.

### Degrade, don't fail   {#degradation}
Full-text needs no external service, so a `[Searchable]` field is useful the instant you deploy. Semantic ranking
is an *upgrade*: declare an embedding for the app and every `Full` / `Memory` field starts ranking by meaning too —
no code change. If you deploy `Full` or `Memory` searchable fields with no embedder configured, the deploy succeeds
and warns that semantic ranking is inactive until you wire one; full-text is live in the meantime.

## Examples       {#examples}
```osy title="entity-local field search (default for String)" test app=memory
using Osysharp.Memory;

entity Article {
  [MaxLength(200)] string Title;
  [Searchable] string Body;            // Entity scope, Full mode — the String default
}
```

```osy title="lexical-only field (no embedder)" test app=memory
using Osysharp.Memory;

entity Note {
  [Searchable(Entity, TextOnly)] string Text;   // full-text keyword search only
}
```

```osy title="corpus fields for turnkey Memory.Search" test app=memory
using Osysharp.Memory;

entity Doc {
  [Searchable(Memory)] string Summary;   // a String explicitly placed in the corpus
  [Searchable] Markdown Body;            // Markdown defaults to the corpus
}
```

## See also       {#see-also}
- [field search (Matches / TextScore / Similarity)](https://osysharp.com/reference/memory/field-search/) — the field primitives (`Matches`/`TextScore`/`Similarity`) for `Entity`-scope fields
- [using Memory (semantic search)](https://osysharp.com/reference/memory/search/) — the turnkey corpus search over `Memory`-scope fields
- [SearchHit](https://osysharp.com/reference/memory/searchhit/) — the result type `Memory.Search` returns
