Search the catalog
{ "name": "search_items", "arguments": { "query": "invoice 2024", "kind": "pdf", "limit": 50 } }| Argument | |
|---|---|
query |
words to match; the operator is and, so all of them must appear |
kind |
pdf, image, text, data, xlsx, doc, email, calendar, contact, pkpass, file |
limit |
clamped to 1–200, 50 by default |
Omit query and the search becomes a match_all — the most recent items, optionally of one kind.
What it matches
Section titled “What it matches”SearchIndex.search runs a multi_match over three fields:
{ multi_match: { query: query, fields: %w[title^2 locator_key body], operator: "and" } }| Field | Holds | Analyzer |
|---|---|---|
title |
the item’s title, boosted ×2 | path |
locator_key |
the key within its resource | path |
body |
Item#body_text |
standard |
The path analyzer tokenizes on / \ - _ . and whitespace, so 2024/invoices/acme-jan.pdf matches
on acme and on invoices.
body is the union of every string extracted by analysis across an item’s references and its
children’s, so a scanned PDF matches on its OCR and an email matches on a word that only appears in
its attachment. Search quality is downstream of analysis — an item synced but
not yet analyzed matches on its path and title alone.
Item.search asks the index for ids and reloads them from Postgres with in_order_of, so results
keep their relevance order while every column comes from the system of record.
Then get one
Section titled “Then get one”{ "name": "get_item", "arguments": { "id": "..." } }Returns every reference, its locator, the per-step analysis results, and body_text truncated to
8,000 characters (Tool::GetItem::EXCERPT).
An item groups references. The same document in a bucket and in Drive is one item with two, not two items.
Getting the bytes
Section titled “Getting the bytes”get_item returns an excerpt, not the file. export_items copies bytes into a storage resource;
the browser reads them at /references/:id/content. See Export.
Isolation
Section titled “Isolation”The application never queries the underlying index — only SearchIndex.alias_for(tenant), an alias
carrying a term filter on tenant_id that the engine applies:
{ add: { index: index, alias: alias_for(tenant), filter: { term: { tenant_id: tenant.id } } } }See Tenancy.
Rebuilding
Section titled “Rebuilding”ReindexItemsJob writes into a fresh versioned index a page at a time, then SearchIndex.promote!
swaps every alias in one update_aliases call. Promotion refuses an index holding fewer documents
than it was told to expect.