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

Query languages

Every search names a language, and WarpSearch translates it into one native query that runs on the same engine. Use whichever language your team, your tools or your existing queries already speak. You can run any of them through the REST API, and the Elasticsearch, OpenSearch and Solr languages are also served by drop-in endpoints for existing clients.

language What you send Typical use
sql One SELECT over one collection Analysts, BI, quick questions
lucene Lucene query_string syntax Search boxes, Kibana and Grafana habits
es An Elasticsearch or OpenSearch _search body Migrations, rich queries, aggregations, kNN
solr Solr request parameters or a JSON Request body Solr migrations
logql A Loki LogQL query Log search and log metrics
grafana A Grafana Elasticsearch data source target Dashboards
luxir WarpSearch's native expression syntax Application-authored queries, with safe variables

The value luxir is the native language's name in the API. Filters, facets, metrics, sorting and paging in a request work the same way whatever the language; see Searching and Facets and aggregations.

Sending a query

curl -X POST https://api.warpsearch.io/v1/search \
  -H "Authorization: Bearer $WARPSEARCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"language": "sql", "query": "SELECT title, year FROM books WHERE year > 1960 ORDER BY year DESC LIMIT 5"}'

POST /v1/search takes the collection from the body's collection field or, for SQL, from FROM. POST /v1/collections/{c}/search puts it in the path. The query is a string, except for es and grafana, where it is a JSON object.

See the translation

POST /v1/translate takes the same body and returns the native form without running it. The response includes the native query, any warnings, and a replay: a request in the native language that you can send to /v1/search to skip translation. Adding "include_translation": true to a normal search puts the same information in its response.

This is the quickest way to learn what an unfamiliar language did with your query, and to check for approximations before you tune relevance.

Rules that apply to every language

SQL

One SELECT over one collection.

SELECT title, year FROM books
WHERE year BETWEEN 1960 AND 1980 AND genre IN ('scifi', 'fantasy')
  AND MATCH(title) AGAINST('dune') AND author LIKE 'Frank%'
ORDER BY year DESC LIMIT 10 OFFSET 20
Supported Notes
=, !=, <, <=, >, >=, IN, BETWEEN, LIKE, REGEXP, IS [NOT] NULL, AND, OR, NOT On a text field = is a phrase match, on a keyword field it is exact.
Full text: MATCH(col) AGAINST('words'), match_query(col, 'words'), match_phrase(col, 'exact words'), query_string('lucene syntax')
Dates: ISO-8601 strings, NOW() - INTERVAL 7 DAY
COUNT(*), COUNT(col), AVG, SUM, MIN, MAX
GROUP BY a, b, HAVING COUNT(*) >= n, ORDER BY <aggregate>, SELECT DISTINCT col Becomes nested terms facets. LIMIT caps the number of groups. HAVING supports COUNT(*) with > and >= only.

Not supported: joins, subqueries, UNION, window functions.

Lucene

Lucene query_string syntax, as typed into Kibana or Grafana. Bare terms search the collection's default fields.

{"language": "lucene",
 "query": "title:dune AND year:[1960 TO 1980] -status:draft author:herb* name:smith~1 \"exact phrase\"~2 _exists_:isbn price:>=10"}

? and * become wildcards, a lone trailing * becomes a prefix query, and /re/ is a regular expression. Use GET /v1/collections/{c}/search?q=... for a one-line version.

Elasticsearch and OpenSearch Query DSL

Send an _search body as the query object.

{"language": "es",
 "query": {"query": {"bool": {"must": [{"match": {"title": "dune"}}],
                              "filter": [{"range": {"year": {"gte": 1960}}}]}},
           "aggs": {"genres": {"terms": {"field": "genre", "size": 5}}},
           "size": 10}}
Area Supported
Full text match, match_phrase, match_phrase_prefix (one word), match_bool_prefix, multi_match, combined_fields, query_string, simple_query_string
Term-level term, terms, ids, exists, range, prefix, wildcard, regexp, fuzzy
Compound bool, constant_score, dis_max, boosting, function_score (weight, field value factor, decays, random score), post_filter
Geo geo_distance, geo_bounding_box, _geo_distance sort
Vectors Top-level knn, the knn query and the OpenSearch knn query, alone or combined with text for hybrid search. num_candidates is capped at 10000. See Vector search and Hybrid search.
Other sort, from/size, _source, track_total_hits, min_score, collapse with inner_hits
Aggregations terms, histogram, date_histogram, range, date_range, filters, filter, global, top_hits, avg, sum, min, max, value_count, stats, extended_stats, cardinality, percentiles, percentile_ranks

Some scores are approximations: best_fields and dis_max sum their clauses instead of taking the maximum plus a tie breaker, and cross_fields does not blend terms. The same documents match, and you get a warning.

Not supported: nested, has_child and has_parent, more_like_this, percolate, scripts, search_after, scroll, point in time, suggest, rescore and runtime_mappings. These answer 400 unsupported_feature. highlight, explain and timeout are accepted with a warning and have no effect.

Coming soon: highlighting and polygon geo queries.

Add ?format=es to /v1/collections/{c}/search for an Elasticsearch-shaped response, or use the compatible endpoints with an existing client.

Solr

Solr request parameters as a query string, or a JSON Request API object.

{"language": "solr",
 "collection": "books",
 "query": "q=dune messiah&defType=edismax&qf=title^2 body&mm=2&fq={!tag=g}genre:scifi&facet=true&facet.field={!ex=g}genre"}

Supported: the standard, dismax and edismax parsers, local params and $param references, fq with tags and exclusions, function queries and bf/bq, sorting (including geodist()), {!geofilt} and {!bbox}, {!knn}, classic and JSON faceting (field, range, query, interval, pivot), stats, and grouping by one field. Solr-shaped responses come from /compat/solr/{collection}/select; see Solr compatibility.

Not supported: joins and block join, collapse, cursorMark, spellcheck, more-like-this, term statistics functions, atomic updates and delete by query.

LogQL

Grafana Loki's query language. Labels are fields, and line filters search the collection's message field.

{"language": "logql",
 "collection": "logs",
 "query": "sum by (host) (count_over_time({app=\"api\"} |= \"timeout\" [5m]))",
 "time_range": {"from": "2026-10-20T00:00:00Z", "to": "2026-10-20T06:00:00Z"},
 "step": "1m"}

Metric queries come back as a date histogram, one series per group. Set the window with time_range and the bucket width with step.

Supported Notes
Stream selectors on labels, such as {app="api", level=~"warn|error"}
Line filters |=, !=, |~ Match words and phrases in the message field, not raw substrings.
json and logfmt stages No-ops, because fields are already indexed.
count_over_time, rate, sum by, avg_over_time with unwrap rate returns counts per bucket.

Not supported: without(), bytes_* functions and binary operations between metric queries.

The Loki push and query HTTP APIs themselves are not offered; see Loki and LogQL.

Grafana

The Grafana Elasticsearch data source target model: query, metrics and bucketAggs, usually with time_range. A date_histogram with interval: auto picks a round width for about 100 buckets.

Native syntax

The native language is for queries your application writes. It has real AND/OR/NOT precedence, and $name variables that are always values and never syntax, so user input cannot change the shape of a query.

{"language": "luxir",
 "query": "title:$q AND year:>=1960 AND status:=live",
 "vars": {"q": "dune messiah"},
 "limit": 10}
Form Meaning
title:dune Word match, analyzed like the field.
title:"dune messiah"~2 Phrase, with slop.
status:=live, status:=(a, b) Exact whole value, one or any of several.
year:[1960 TO 1970], year:>=1965 Range. { } excludes an endpoint, * leaves it open.
created:>=NOW/DAY-30DAYS Date math.
title:mess*, author:Herbet~1, year:* Prefix, fuzzy (up to 2 edits), field exists.
+title:dune -tag:beta, title:dune^2 Required, excluded, boost.
wildcard(du*, field=title), regex(dune|kings, field=title) Wildcard and regular expression, whole term.
simple_query($input, fields=[title, body]) Forgiving search-box syntax that never fails to parse.

There is no default field: name one. ? and mid-word * are ordinary characters, and the pattern queries above are functions.

Compatible endpoints

Keep your client and point it at WarpSearch with the same API key:

Client Base URL
Elasticsearch https://api.warpsearch.io/compat/es
OpenSearch https://api.warpsearch.io/compat/opensearch
Solr https://api.warpsearch.io/compat/solr/{collection}

See Elasticsearch compatibility, OpenSearch compatibility and Solr compatibility. Agents can run all of the languages above through the MCP search and translate_query tools; see Guide for AI agents.

View this page as Markdown