
# Full-Text Search

Tables declare _what_ is searchable. Three field-level properties control how a field participates in search: `indexed` makes it queryable, `searchWeight` ranks its relevance, and `fullTextSearch` (on `rich-text`) enables FTS indexing for formatted content. Components then pick the engine that consumes these — see [search-overview](/en/docs/search-overview#search-engines).

## Field properties

| Property         | Applies to      | Description                                                                                                        |
| ---------------- | --------------- | ------------------------------------------------------------------------------------------------------------------ |
| `indexed`        | All field types | Boolean. Creates a database index on the field. Required for `fts`, `trigram`, and `hybrid` engines.               |
| `searchWeight`   | All field types | `A`–`D`. PostgreSQL FTS relevance weight. Only effective when `indexed: true` and the engine is `fts` or `hybrid`. |
| `fullTextSearch` | `rich-text`     | Boolean. Enables full-text-search indexing for the field's formatted content.                                      |

These extend the [base field properties](/en/docs/tables-overview#base-field-properties) shared by every field type.

## Field relevance weights

`searchWeight` maps directly to PostgreSQL FTS weights, ordering how strongly a match in each field influences the relevance rank. A title match outranks a body match.

| Weight | Relevance | Typical fields                       |
| ------ | --------- | ------------------------------------ |
| `A`    | Highest   | Title, name, headline.               |
| `B`    | High      | Description, summary, excerpt.       |
| `C`    | Medium    | Tags, categories, labels.            |
| `D`    | Lowest    | Internal notes, metadata, footnotes. |

```yaml
tables:
  - name: articles
    fields:
      - { id: 1, name: title, type: single-line-text, indexed: true, searchWeight: A }
      - { id: 2, name: summary, type: long-text, indexed: true, searchWeight: B }
      - { id: 3, name: tags, type: single-line-text, indexed: true, searchWeight: C }
      - { id: 4, name: body, type: rich-text, indexed: true, fullTextSearch: true, searchWeight: B }
```

:::callout
`searchWeight` is only meaningful when the field is `indexed: true` **and** a data source queries it with `searchEngine: 'fts'` or `'hybrid'`. With `client` or `trigram` engines the weight is ignored.
:::

## `fullTextSearch` on rich text

The `rich-text` field stores formatted HTML. Setting `fullTextSearch: true` enables full-text-search indexing of its text content so the field can participate in `fts`/`hybrid` queries alongside plain-text fields.

```yaml
- id: 5
  name: article_content
  type: rich-text
  required: true
  maxLength: 10000
  fullTextSearch: true
  searchWeight: B
  toolbar: [bold, italic, link, heading, list]
```

Plain `long-text` and `single-line-text` fields do not need `fullTextSearch` — set `indexed: true` and a `searchWeight`, and they are FTS-ready. The `fullTextSearch` flag exists specifically for `rich-text` because its stored value is HTML markup rather than plain text. See [text-fields](/en/docs/text-fields#rich-text) for the full `rich-text` property set.

## PostgreSQL vs SQLite

| Aspect             | PostgreSQL                                            | SQLite                                                 |
| ------------------ | ----------------------------------------------------- | ------------------------------------------------------ |
| FTS engine         | Native `tsvector`/`tsquery` with weighted ranking.    | Simpler matching; weighted ranking is reduced.         |
| Fuzzy matching     | `pg_trgm` extension (trigram, typo-tolerant).         | Not available — trigram engine targets Postgres.       |
| `searchWeight` A–D | Fully honored in relevance ranking.                   | Best-effort; weight ordering may be approximate.       |
| Recommendation     | Use for index-backed `fts`/`trigram`/`hybrid` search. | Zero-config default; design ranked search on Postgres. |

:::callout
SQLite is Sovrium's zero-config default database. For production search that depends on ranked relevance (`searchWeight`) or fuzzy matching (`trigram`/`hybrid`), run against PostgreSQL where `tsvector` and `pg_trgm` are available.
:::

## Trigram fuzzy matching

The `pg_trgm` extension breaks text into three-character sequences (trigrams) and matches on overlap, tolerating typos and partial words. This powers the `trigram` and `hybrid` engines. A field used for fuzzy search should be `indexed: true` so PostgreSQL can build a trigram (GIN/GiST) index.

```yaml
tables:
  - name: products
    fields:
      - { id: 1, name: name, type: single-line-text, indexed: true, searchWeight: A }
```

```yaml
# Component side — fuzzy matching on the indexed field
- type: data-table
  dataSource:
    table: products
    mode: search
    searchFields: [name]
    searchEngine: trigram
```

A query of `prodct` still matches `product`; `lapto` matches `laptop`. Pair trigram with FTS using `searchEngine: 'hybrid'` to keep relevance ranking for exact terms while retaining typo tolerance for the rest.

## Related

- [Search Overview](/en/docs/search-overview) — the four search engines and the `search` data-source mode.
- [Search Components](/en/docs/search-components) — `searchInput`, `list`, `pageSearch`, and toolbar search.
- [Text Fields](/en/docs/text-fields) — `rich-text`, `long-text`, and the `fullTextSearch` flag.
- [Tables Overview](/en/docs/tables-overview) — `indexed`, `searchWeight`, and other base field properties.
