Skip to content
ferroseekdocumentation homemain, packages at version v0.1.0
Ferroseek on GitHub

Queries

Queries go in the query (and post_filter) of a _search body, in the query of a _count body, and inside filter and filters aggregations. They are written exactly as for Elasticsearch 7.17. A parameter that is not listed here is either rejected as unsupported or, if Elasticsearch does not know it either, answered with Elasticsearch’s own parsing error.

text fields are analyzed with the Elasticsearch standard analyzer: Unicode word segmentation, lowercasing, no stop words, no stemming. Custom analyzers are not available, and the analyzer parameter is rejected wherever it appears.

Scoring is BM25 with Elasticsearch’s defaults (k1 = 1.2, b = 0.75), including Lucene’s lossy one-byte storage of field lengths. That is what makes scores match a real Elasticsearch to within 1e-4 and hits come back in the same order.

{ "query": { "match": { "name": { "query": "wireless speaker", "operator": "and" } } } }
Parameter Values
query The text to search for (short form: {"match": {"name": "wireless speaker"}})
operator or (default) or and
minimum_should_match A count (2) or a percentage ("75%"); conditional forms such as "3<90%" are rejected
boost Number
fuzziness, prefix_length, max_expansions, fuzzy_transpositions See typo tolerance

Rejected: analyzer, lenient, zero_terms_query, cutoff_frequency, auto_generate_synonyms_phrase_query, fuzzy_rewrite.

Searches several fields. Field names may carry a boost: "name^3".

{
"query": {
"multi_match": {
"query": "wireless speaker",
"fields": ["name^3", "description"],
"operator": "and"
}
}
}
Parameter Values
query The text
fields Required; wildcards such as "name*" are rejected
type best_fields (default), phrase or phrase_prefix
operator or or and (best_fields)
tie_breaker Number; how much the other matching fields add to the best one
slop For phrase and phrase_prefix
max_expansions For phrase_prefix; with best_fields it belongs to fuzziness
fuzziness and friends best_fields only; with phrase or phrase_prefix they are an error, as in Elasticsearch
boost Number

Rejected: the types most_fields, cross_fields and bool_prefix; minimum_should_match with best_fields; omitting fields (Elasticsearch would fall back to index.query.default_field).

Matches the terms in order. slop allows that many position moves between them.

{ "query": { "match_phrase": { "description": { "query": "wireless speaker", "slop": 1 } } } }

Parameters: query, slop (default 0), boost. Rejected: analyzer, zero_terms_query, _name.

A phrase whose last term is a prefix, for search-as-you-type:

{ "query": { "match_phrase_prefix": { "name": { "query": "wireless sp", "max_expansions": 50 } } } }

Parameters: query, slop, max_expansions (how many terms the prefix may expand to, default 50), boost.

Each term must match (or should match, with the default or operator), and the last one as a prefix. Parameters: query, operator, boost. Rejected: analyzer, minimum_should_match, fuzziness, prefix_length, max_expansions.

match and multi_match (type best_fields) accept fuzziness, which lets each analyzed term match terms within an edit distance:

{
"query": {
"match": {
"name": { "query": "wireles speakr", "fuzziness": "AUTO" }
}
}
}

Against the sample catalog this still finds “Zakeli Wireless Speaker” first.

Parameter Values
fuzziness "AUTO", "AUTO:low,high", 0, 1 or 2. AUTO allows no edit for terms shorter than 3 characters, one edit up to 5, two from 6
prefix_length Number of leading characters that must match exactly (default 0)
max_expansions How many candidate terms each term may expand to (default 50; at most 1024 are used)
fuzzy_transpositions true (default) counts a swap of two adjacent characters as one edit

An exact match scores higher than a corrected one: each candidate term is weighted by how close it is to what was typed. With several terms in one match, scoring can differ slightly from Elasticsearch in one rare case; see Limits and differences.

The standalone fuzzy query is not supported; use match with fuzziness.

These do not analyze their input. Use them on keyword, numeric, boolean and date fields.

Query Example Notes
term {"term": {"brand": "Lanfe"}} Long form {"term": {"brand": {"value": "Lanfe", "boost": 2}}}
terms {"terms": {"color": ["red", "blue"]}} Up to 65,536 values
range {"range": {"price": {"gte": 20, "lt": 80}}} gt, gte, lt, lte on numbers and dates
exists {"exists": {"field": "rating"}} Documents with a value in the field
ids {"ids": {"values": ["SKU-000001"]}} Up to 65,536 ids
prefix {"prefix": {"sku": "SKU-0001"}} On keyword and text fields

Dates are given as ISO 8601 ("2025-03-14", "2025-03-14T09:26:53Z") or as epoch milliseconds. Date math such as "now-7d" is not supported, and neither are the range parameters format, time_zone, relation, from, to, include_lower and include_upper.

match_all and match_none take an optional boost. constant_score wraps a filter and gives every match the same score (its boost, default 1).

Combines queries:

{
"query": {
"bool": {
"must": [{ "multi_match": { "query": "wireless speaker", "fields": ["name^3", "description"] } }],
"filter": [
{ "term": { "in_stock": true } },
{ "range": { "price": { "gte": 20, "lte": 400 } } }
],
"must_not": [{ "term": { "brand": "Lanfe" } }]
}
}
}
Clause Effect
must Must match; contributes to the score
filter Must match; does not score
should Adds to the score; with no must or filter, at least one must match
must_not Must not match
minimum_should_match How many should clauses must match: a count or a percentage
boost Number

bool queries nest up to 20 levels deep, as in Elasticsearch. Rejected: adjust_pure_negative.

These query types are rejected with 400 illegal_argument_exception and a reason starting [ferroseek] unsupported:: fuzzy, wildcard, regexp, dis_max, function_score, query_string, simple_query_string, nested, script, script_score, boosting, combined_fields, geo_distance, more_like_this. Named queries (_name) are rejected too. A query type that Elasticsearch does not know either answers parsing_exception (“unknown query”), as Elasticsearch does.