AACSearch / guide
Search and relevance
Preview and playgrounds, search rules and merchandising, synonyms, curation, stopwords, stemming, presets, aliases, semantic and image search, query intelligence and NL models.
Search configuration lives in two layers: per-collection documents (search rules, synonyms, stopwords, stemming, synonyms sets) and account-wide defaults (presets, aliases, query policies). The relevance screens are grouped under Search → Relevance in the sidebar.
Search preview
/dashboard/search is the visitor-facing search page rendered live over one
collection. It runs in the browser with a short-lived, search-only preview key
minted by the console (keys.preview) — never the organization's full key.
- Widgets — search box with voice input, related searches, search rules, and a Filters panel with hierarchical menu, refinement list, range input, rating menu, toggle refinement and clear-refinements. Plus stats, sort-by, hits-per-page (12 / 24 / 48), current refinements, search status, hits, no-results and pagination.
- Config from the schema —
query_byis built from the string fields; facets come from the schema (string → searchable list, bool → toggle, numeric → range or a rating menu when the field looks like a rating,*.lvlN→ hierarchical), capped at eight; sorting offers relevance plus price when a price-like field exists. - AI answer — a switch that adds
conversation: trueand the first registeredconversation_model_idto the query and renders the answer inline. It is disabled only while the model list is loading; with no model it can still be turned on, and then shows a link to Conversation models. - Response extensions — a
redirectfrom a matching rule is shown as a link (not followed),query_rewriteis surfaced around the no-results state, andsuggestionsbecome related searches and refinement chips. - Hit detail — opening a hit shows the raw document in a drawer with the query terms marked.
- Embed — the header dialog emits the widget snippet for this collection.
The collection is chosen in the header and kept in ?collection=, so a search
preview is a shareable link. With no collection yet, the empty state offers
Create a collection and Guided setup.
Search playground
/dashboard/playground/search is the raw-hit "chunk explorer" — the screen to
reach for when a result looks wrong. It runs on the same short-lived search-only
preview key as the preview; without one it shows a "No preview key" empty state
pointing at Guided setup. A ?q= parameter seeds the initial query.
- Pick the collection, then set
query_bywith checkboxes or a free-text comma list (the free text wins). Earlier fields weigh more, and the screen shows the effective list. - Set the page size (10 / 20 / 50 / 100), and optionally limit the search to a
chosen set of documents: the picker loads the first 100 with
q=*, is searchable, multi-selects, reports "First N of M documents", and turns the selection intofilter_by=id:=[…]; Clear document limit removes it. - Rerank turns on
rerank=truewith a model (bge-reranker-basecross-encoder orllm) and notes that reranked hits carryrerank_scoreand that each call costs credits. - Debug (on by default) requests
debug=true, which returns_traceand per-hit_explain. The page prints the equivalentGET …/documents/searchcall, so a playground experiment can be replayed from code.
With debug on, a collapsed trace panel can be expanded to show badges for
index status, index time, total time, the exclusion filter, matched boosts,
pins, diversity drops, rewrite and fallback, along with stage timings. Hits are
shown as stored, each with score, rerank_score and vector-distance badges and
Explain / View JSON toggles for the raw engine object.
Chat playground
/dashboard/playground is the live assistant chat. It is gated by the plan's
voice feature — not assistants — so on a plan without voice the screen
shows the upgrade explanation.
- The header selects the assistant (only ids the organization actually has; a
?assistant=deep link is honoured, andNEXT_PUBLIC_NOVA_ASSISTANT_IDis a fallback only when it is in the list). The selector is disabled while loading or when there are no assistants. - New chat clears the current sources and starts a fresh conversation.
- Chat parameters overrides a single turn: a
filter_by, the maximum number of sources (1–40, defaulting to the assistant's own setting) and auser_id, with Reset and Save. - The API dialog shows cURL, TypeScript and Python examples for
POST /assistants/{id}/chat/completions/stream, notes that a search-scoped key may call it from a browser when it also sendsX-NOVA-SESSION-ID, and links to create a key. - The layout is the conversation history, the transcript, and an Assistant / Sources column showing the assistant's collections, model and active overrides; a cited source opens its document in a drawer. On mobile the history and the assistant column become sheets.
Without an assistant the screen links to Assistants; a failed load shows an inline error. The first completed turn ticks the quick-start playground step.
Ranking Studio
/dashboard/ranking (open /dashboard/ranking directly — it is not in the
sidebar) summarises the four places ranking is shaped and whether each is in
use: search rules, presets, query policies and personalization.
It leads with an "N of 4 ranking sources in use" count and a Refresh, and
the four cards load independently: if one source fails, that card shows an
Unavailable badge and its error while the rest still render. Each card is
Active or Not configured and carries its own counts — collections with
rules, boosts and pins; the number of presets; tenant policies against the
built-in ladder; and whether personalization is enabled, configured and
applied.
It states the order they are applied — query policies (channels, correction,
rescue) → presets (query_by, filters, sorting) → search rules (boost, pin,
sponsor, diversify) → personalization — and links to the Quality lab.
Search rules
/dashboard/search-rules lists one rule document per collection: zero-hit
fallback, and counts of boosts, pins, sponsored placements, banners, redirects,
diversity entries and rerank. The list requires the search_rules plan feature
and offers New, which asks for a collection (pick one or type a new name)
and opens its editor; ?collection=… jumps straight there. Like the other
shared list screens it has a Refresh, a row count, a filter box once there are
six or more rows, and a quota-exceeded state. A row can be deleted, with a
confirmation, and the collection then falls back to default rules.
/dashboard/search-rules/{collection} is the merchandising editor. Saving
validates through the control plane (rules.lint) and shows warnings above the
save button — warnings never block a save. Sections:
| Section | What it configures |
|---|---|
| Defaults | An exclusion filter_by ANDed onto every search, the zero-hit fallback (none, broaden_query to drop caller filters, or a recommendation model), and whether boosts override the requested sort. |
| Boosts | A filter_by, a weight (negative lowers) and a name. |
| Pins | A document id, a 0-based position, and an optional query with exact / prefix / contains matching. |
| Sponsored | An id, position, label (default "Sponsored"), optional query + match, and a filter_by. The hit is marked _sponsored. Omitting both triggers applies it to every search. |
| Banners | An id, priority, optional query + match, a filter_contains, and a required JSON content object (for example {heading, image_url, link}). |
| Diversity | Caps per field (field, max, min, from), near-duplicate suppression over text fields with a Jaccard threshold (default 0.9), and MMR (lambda default 0.7, k, a vector_field or text fallback). Applied in the order near-duplicates → caps → MMR → floors. |
| Rerank | An enabled by default switch (off still allows a per-request rerank=true), the model, top_k (default 20), timeout_ms (default 400) and the passage fields. Reranking is metered in credits. |
| Redirects & suggestions | Query → URL redirects (response carries redirect.url), query suggestions, and facet-suggestion fields that build "phone Apple"-style refinements. |
| Schedule & audience | Start and end timestamps, device, language and country. Blank applies to every request. |
The zero-hit fallback to a recommendation model also requires a
fallback_model_id.
Admins also get two panels:
- Preview — takes a query, states that nothing is saved or metered, and prints a per-side "fired" summary of what the candidate rule would do (exclusion, boosts, a redirect with its URL, pins, sponsored placements, banners, suggestions, diversity, fallback) beside the live rule, with a diff.
- Versions — history with a latest badge, badges for source (console, API, rollback, suggestion) and deletion, a note column, relative time with an exact timestamp on hover, and a per-version View showing that snapshot and its diff against the current rule. Roll back is disabled on the newest version and writes a new version rather than rewriting history.
Synonyms
/dashboard/synonyms manages synonym sets. Each line of the Groups field is
one rule:
айфон, iphone, apple phone # every term finds the others (multi-way)
кроссы => кроссовки, sneakers # one-way rewrite
# comments are skippedA non-arrow line with fewer than two terms is rejected with the line number. Creating a set that already exists replaces it — there is no separate edit screen. Deleting a set stops its groups expanding queries immediately; searches keep working. The list shows each set's group count and a For example column with the first two groups as badges (the rest behind a tooltip, up to twelve), and a row's JSON can be viewed. There is no CSV import.
Synonym suggestions
/dashboard/synonym-suggestions mines zero-hit and popular queries and proposes
synonyms, per collection. A status filter switches between pending (the
default), accepted, rejected and all. Generate reads the last 30 days of
events (or a seeded query) and reports how many queries it examined, how many
suggestions it produced and how many it skipped. Pending suggestions can be
accepted into a synonym set or rejected, and any suggestion can be
deleted; accepted rows show the set they joined.
The table carries the query, the suggested term (and the candidate it came
through), the kind, status, how often the query was found and seen, and sample
titles. Search issues deep-links here with ?collection= and ?query=, in
which case the generate button reads Generate for query.
Curation
/dashboard/curation holds rule sets that pin, hide, rewrite or re-sort results
for named queries. The curation plan feature is required. The list shows each
set's description, its rule count and a Reacts to column — the first three
triggers, with up to ten trigger → effect pairs in a tooltip — plus a filter
box and a per-row JSON viewer. Creating a set takes only a name and description;
deleting one, after confirmation, makes the queries it covered fall back to
plain relevance.
The rules editor works on cards and replaces the whole set when saved. Each
rule matches on a query (any / exact / contains) or a filter_by, and
can:
- include (pin) documents at a position,
- exclude (hide) documents,
- replace the query,
- override
sort_by, - and stop processing further rules.
Blank rules are dropped, and keys the form does not edit (tags, metadata,
time windows) survive a round trip. Rules are matched in set order. Per
request, curation_tags limits curation to rules carrying those tags, and
enable_curations switches curation on or off for that search.
Stopwords and stemming
/dashboard/stopwords manages stopword sets — a set id, a locale label and the
words (comma or newline separated). The locale is only a label and does not
change matching. Deleting a set makes its words searchable again and stops any
search rule that named it from applying.
/dashboard/stemming imports word → root pairs so searches match other forms.
The parser accepts →, ->, =>, =, tab, comma, semicolon, two or more
spaces, a single space, a bare JSON object, or a JSON array of {word, root},
and skips # comment lines; a bad line is reported with its number, and
duplicate words are rejected. A dictionary is
replaced by importing the same id again — the API does not allow deleting one.
The list loads the mappings for the first 25 dictionaries only; later rows show
no count or sample until you open them. A dictionary can be browsed (first 500
rows, filterable by word or root, with "Showing the first 500 of N — download
the JSONL for the rest") and downloaded as JSONL.
Presets and aliases
/dashboard/presets stores named bundles of search parameters that a request
applies with preset=<id>; the request's own parameters win. The list has a
debounced name filter (press / to focus, Esc to clear, with an "N of M"
counter), a Kind badge distinguishing a single search preset from a
multi-search array, and a per-row JSON viewer of the stored value. The editor
is form-first (query_by, sort_by, filter_by, per_page — the last must be
a positive whole number) with a JSON mode for anything else, including
multi-search arrays. Keys the form does not render are preserved. Saving writes
PUT presets/{id}, so creating under an existing id replaces it; an id cannot
be renamed. A transient "Saved. The preset is live." line confirms the write,
failures render a Retry card, and deleting a preset makes every request that
sends it fail at once.
/dashboard/aliases points a stable virtual collection name at a real
collection — the pattern for a pointer-flip reindex. Creating an alias that
exists re-points it, which is how a reindex goes live. The form offers the
organization's collections and rejects a name that does not exist. The
Documents column shows the target's document count, or a destructive
"missing" badge when the target is gone, and the target links to its collection
screen. If the target does not exist the screen warns that searches through the
alias fail with a 404. The target collection is never touched by deleting an
alias — the confirmation says so — but searching through the alias breaks
immediately.
Semantic and image search
/dashboard/vector-search ("Semantic & image") requires the semantic_search
plan feature. It has two tabs:
- By meaning — type a sentence in any language and search the collection's vector field.
- By image — drop a file (PNG / JPEG / WebP / GIF) or give a public image URL. The image is embedded as media (the screen polls the media record while the vision model runs, with a 45-second timeout) and then used to search.
Both share a vector-field selector, a result count k (1–50, default 12), a
minimum-similarity slider (sent as a distance threshold) and an optional
Filter expression (filter_by) applied to both kinds of search. The
collection and tab round-trip through ?collection= and ?tab=meaning|image,
so a vector search is a shareable link, and the header offers a Keyword
preview that opens the same collection in the search preview. Collection
options show their document count and mark those with vectors.
Results show similarity as 1 − cosine distance, with the raw distance in a
tooltip, plus found and search_time_ms; each result offers Open, which
jumps to the document browser filtered to that id. Vector fields are stripped
from the returned documents. For an image search, a "What the model sees" panel
shows the caption, an embedding status badge (pending / ready / failed), the
media id, size and dimensions. The empty state explains that the collection
needs a float[] field (the platform's own embedding model produces 1024
dimensions) and links to the schema editor.
Query intelligence
/dashboard/query-intelligence exposes how a query is understood before the
engine runs it. A collection picker at the top scopes every tab and round-trips
through ?collection=; with no active organization, or with no collections, the
page shows an empty state that links to create one. It has four tabs:
- Debugger — inputs are the query, a policy override (auto-match, or a
named built-in or tenant policy), the surface to simulate (
search,autocompleteorpresearch), optional engine-parameter JSON and a "Run search" switch. Output is the full pipeline: normalised text, intent, relation, strategy, policy, script, confidence, product type, brands, identifier-only flag and lexical/semantic channels; protected tokens; entities; constraints with their hardness (hard / soft / negative) and generatedfilter_by; tokens and segments with drop priority; scored hypotheses and corrections, with the chosen correction, its reason and the alternatives; and the execution plan. With "Run search" on, the real search runs and its timings, refinement chips, understanding and trace are shown alongside. - Policies — the built-in ladder (read-only) plus tenant policies. A policy
has a name, an optional collection (blank = all), a priority (higher wins,
0–100000), an enabled flag, and JSON
matchandplanblocks; its row also shows the version and when it was last updated. Built-in names cannot be reused. Deleting a policy falls back to the next by priority. - Entities — canonical entities with aliases and a type, searchable and
filterable. Each row shows the canonical form, type, aliases, coverage, the
collection, whether it is enabled and where it came from (
manualor afacet:<field>bootstrap), with per-row edit and delete. Aliases are auto-completed with transliteration and keyboard-layout variants. Bootstrap from facet builds entities from a string facet field (up to 2000 values). - Graph & stats — suggestion impressions, lists, selects, chip clicks, graph edges, candidates and entity counts over a 1 / 7 / 30 / 90-day window; a rebuild for the graph and suggestions; and a neighbour lookup showing transitions, successes and score. The graph is rebuilt nightly from session sequences.
Writes (policies, entities, bootstrap, rebuild) are owner/admin actions.
Natural-language search
/dashboard/nl-search manages NL search models, gated by the nl_search plan
feature. Each model has an id, a provider/model name (for example
openai/gpt-4o-mini) and an optional API key — the platform stores the key and
never returns it; leaving it blank uses the platform's credentials. A row's
action links to the search playground naming this model
(nl_query=true&nl_model_id=…); the playground reads only q today, so the
rewrite itself is exercised by sending nl_query and nl_model_id (plus
nl_query_debug for the raw model response) to the search API, whose response
carries parsed_nl_query.
Each rewrite is a model call billed in credits, and nothing here changes ordinary keyword search. Deleting a model means requests that name it fall back to the query as typed.