Skip to main content
Splendor exposes three ways to search, and they share one response shape. Whether you run a keyword query, a SQL projection, or a semantic lookup, you get back the same envelope with the same fields — so you can switch modes without rewriting how you read results.

The three modes

Keyword and full-text search with relevance ranking. Send text (or q) with the datasets to search. Scores are bm25.
{
  "text": "connection timeout",
  "datasets": ["app-logs"],
  "limit": 20
}
Add structured where filters, a time range, and aggregations to narrow and summarize. A filter-only request (no text) browses records that match the filter.

The response envelope

Every mode returns this shape. The fields make truncation explicit so you never have to guess whether more results exist.
{
  "search_id": "srch_...",
  "mode": "text",
  "datasets": ["app-logs"],
  "returned": 20,
  "limit": 20,
  "total": { "value": 1240, "relation": "eq" },
  "has_more": true,
  "next_cursor": "opaque-or-null",
  "route": "hot",
  "wall_ms": 183.4,
  "results": [ /* normalized results */ ],
  "aggregations": {}
}
FieldMeaning
search_idA handle for paging, export, or saving a view.
total{ value, relation }. relation is eq, gte, or unknown. Semantic totals are always unknown.
has_more / next_cursorWhether more results exist and the opaque cursor to fetch them.
routeWhere the query executed: hot, cold_lambda, or async_export.
truncated_reasonPresent when results were capped — for example max_candidates or export_required.
Each result is normalized to a common form regardless of mode:
{
  "id": "rec_...",
  "body": "canonical text",
  "snippets": ["matched text"],
  "score": 12.4,
  "score_kind": "bm25",
  "provenance": { "dataset_id": "...", "source": "...", "line": 123 }
}

Readiness gates which modes work

A dataset answers text and sql queries once it is text-search ready, and semantic queries once embeddings are built. Check readiness before relying on a mode. Semantic search additionally requires the tenant’s semantic backend to be configured; when it is not, semantic requests return a clear error.
Prefer refining a query over walking pages. When has_more is true, narrowing your text, where, or time usually beats fetching cursor after cursor — and for exhaustive traversal, use an export or a view instead.