For AI agents: this page is also available as Markdown at /docs/searching.md. Every docs page is: add .md to its URL. llms.txt lists them all.

Searching

A search names a query language, a query, and optionally filters, sorting, paging and the fields to return. WarpSearch runs it over one consistent view of the collection and returns ranked hits, plus any facets and metrics you asked for, in one response. This page covers the request and response. The languages themselves are in Query languages, analytics in Facets and aggregations, and vectors in Vector search and Hybrid search.

curl -X POST https://api.warpsearch.io/v1/collections/books/search \
  -H "Authorization: Bearer $WARPSEARCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "language": "lucene",
    "query": "title:dune",
    "filters": ["year:[1960 TO 1980]", "genre:scifi"],
    "sort": ["year desc"],
    "fields": ["title", "year"],
    "limit": 10
  }'
{
  "took_ms": 3,
  "collection": "books",
  "total": 2,
  "offset": 0,
  "hits": [
    {"id": "b2", "fields": {"title": "Dune Messiah", "year": 1969}},
    {"id": "b1", "fields": {"title": "Dune", "year": 1965}}
  ]
}

The request needs a viewer role or higher. The collection can be in the path (/v1/collections/{c}/search) or in the body (POST /v1/search, where SQL takes it from FROM).

Request fields

Field Meaning
language Required. sql, es, lucene, solr, logql, grafana or luxir (the native syntax). See Query languages.
query The query. A string for most languages, a JSON object for es and grafana. Omitted means match everything.
collection The collection, when you use POST /v1/search.
filters An array of non-scoring restrictions, written in the request's language. They narrow the matches without changing scores.
sort An array such as ["year desc", "_score"].
offset, limit Paging. Both count hits.
fields Which fields to return for each hit.
facets, metrics Analytics over all matches. See Facets and aggregations.
vars Values for $name placeholders in native queries. Never parsed as syntax.
time_range {"from": ..., "to": ..., "field": ...}: restrict to a time window. Handy with logs and grafana.
time_zone Zone for date literals, date math and calendar buckets, for example America/Denver.
default_operator OR (default) or AND for bare words in a Lucene-style query.
track_total Default true. Set false to skip counting every match.
scores Default true. Set false to skip returning scores.
include_translation Adds the native form of your query to the response.

Unknown fields in the request are rejected, so a typo is an error, not a silently ignored option.

For quick checks there is also GET /v1/collections/{c}/search?q=...&limit=...&offset=...&sort=year:desc&fields=title,year, which runs q as a Lucene query.

Filters versus query

Put what should rank documents in query and what should only include or exclude them in filters. A filter does not affect scores and is cheaper. Typical filters are tenant, category, status and date range.

{
  "language": "es",
  "query": {"match": {"title": "dune"}},
  "filters": [{"term": {"genre": "scifi"}}, {"range": {"year": {"gte": 1960}}}]
}

Sorting

Sort by a field, by relevance, or by several keys in order: ["genre", "year desc", "_score"]. A sort without a direction is ascending for fields and descending for _score. Documents missing the sort value come last in either direction.

Sort on keyword, number and date values (the es language can also sort by geo distance). A text field cannot be sorted by its whole value, so give it a keyword sub-field; see Schemas and field types.

Paging

Paging is offset based: limit is the page size and offset the number of hits to skip.

{"language": "lucene", "query": "title:dune", "limit": 20, "offset": 40}

offset + limit cannot exceed your plan's result window, and limit cannot exceed the plan's maximum page size; either answers 422 limit_exceeded. Deep pages cost more than shallow ones because the engine keeps offset + limit candidates. Show a few pages and let people narrow with filters rather than offering page 500.

Not supported: cursors, search_after, scroll and point in time. Use filters (for example on an increasing id or date) to walk through a large result set.

Counting

total is the exact number of matches by default, which means evaluating every matching document. When you do not display a total, set "track_total": false and the query can skip documents that cannot reach the top results. That makes broad queries on large collections much faster and cheaper. To count only, use the count endpoint:

curl -X POST https://api.warpsearch.io/v1/collections/books/count \
  -H "Authorization: Bearer $WARPSEARCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"language": "lucene", "query": "genre:scifi"}'
# {"count": 1204, "took_ms": 2}

Coming soon: a bounded total hit count (10000+) that is cheaper than an exact one.

Choosing fields

fields limits what comes back, which keeps responses small and cheap. Without it you get every retrievable field, except vectors and geo points. Name a vector field to get it back. Hits that lack a requested field simply omit that key.

Coming soon: a stored _source copy of each document, and highlighting.

Not supported: highlighting and snippets today, suggesters and autocomplete, and more-like-this.

What each query type does

You write It does
A word (dune) on a text field Matches the word after analysis (case folded, stemmed for English fields) and scores with BM25.
A phrase ("way of kings") Matches the words in order. A slop ("way kings"~2) allows words in between.
A value on a keyword field Matches the whole value exactly.
A prefix, wildcard, regex or fuzzy term Matches indexed terms. Wildcard and regex depend on your plan. Fuzzy allows up to 2 edits.
A range (year:[1960 TO 1980]) Compares numbers, dates or terms. Dates accept date math such as now-30d.
A knn clause Finds nearest vectors; see Vector search.
Geo distance or box Matches points within a radius or rectangle, through the Elasticsearch and Solr languages.

Geo queries are available in the es language (geo_distance, geo_bounding_box, and sorting by _geo_distance) and in solr ({!geofilt}, {!bbox}, geodist()).

Coming soon: polygon geo queries.

Dates and time zones

Dates in queries are interpreted in UTC unless the request sets time_zone. A partial date matches its whole window: 2026-06 is all of June. With a zone set, now/d starts at local midnight and calendar buckets follow local days across daylight-saving changes. Documents are always ingested in UTC, so write an explicit Z or offset when the exact instant matters.

Warnings

A request can succeed with warnings, an array of strings. They tell you when WarpSearch approximated something instead of rejecting it, for example a score approximation in an Elasticsearch multi_match or an analyzer that fell back to standard. Read them while you are building. Compatible endpoints also send them in a Warning: 299 response header.

Result shape

Field Meaning
took_ms Time spent on the search.
total Number of matches (exact unless track_total is false).
hits The page: each hit has id, score and fields.
facets, metrics Present when requested.
translation Present with include_translation.
warnings Approximations and adjustments.

Pass ?format=es on POST /v1/collections/{c}/search to get an Elasticsearch-shaped response instead.

Errors

Status Code Meaning
400 query_error The query could not be parsed. The detail says where.
400 unsupported_feature The query uses something WarpSearch does not offer.
400 invalid_field A field name does not exist or is not allowed.
403 forbidden Your key lacks the role on this collection.
404 not_found No such collection, or you have no role on it.
422 limit_exceeded A plan limit such as page size, result window, clauses or facets.
429 rate_limited Slow down; honor Retry-After.
503 warming_up The collection is loading. Retry after Retry-After.
504 timeout The request ran past your plan's time limit. Narrow it with filters.

Full list and handling advice in Limits and errors.

Tips

View this page as Markdown