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#
using Osyrin.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#
A [Searchable] field participates in relevance search. What you get is governed by two orthogonal axes.
Scope — where the searchable content lives#
Entity— the field is indexed on its own row, for entity-local field search. You query it with the field primitivesProp.Matches(q),Prop.TextScore(q), andProp.Similarity(q)and compose your own ranking (see field search (Matches / TextScore / Similarity)). This is the default for aStringproperty.Memory— the field's text is chunked into the app's shared corpus, the cross-entity store that using Memory (semantic search) searches with one turnkey call. This is the default for aMarkdownproperty (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#
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.TextOnlyapplies toEntityscope only — the shared corpus is always hybrid, so[Searchable(Memory, TextOnly)]is rejected.
Degrade, don't fail#
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#
using Osyrin.Memory;
entity Article {
[MaxLength(200)] string Title;
[Searchable] string Body; // Entity scope, Full mode — the String default
}using Osyrin.Memory;
entity Note {
[Searchable(Entity, TextOnly)] string Text; // full-text keyword search only
}using Osyrin.Memory;
entity Doc {
[Searchable(Memory)] string Summary; // a String explicitly placed in the corpus
[Searchable] Markdown Body; // Markdown defaults to the corpus
}See also#
- field search (Matches / TextScore / Similarity) — the field primitives (
Matches/TextScore/Similarity) forEntity-scope fields - using Memory (semantic search) — the turnkey corpus search over
Memory-scope fields - SearchHit — the result type
Memory.Searchreturns