When would you expose query_string versus simple_query_string to end users in Elasticsearch?
answer
- one of them fails loudly on bad input
- user typing is never valid syntax
- the smaller operator set can be switched off
- think about which fields a user can reach
- wildcards and regexes are cheap to type
basics
~20 sPrefer simple_query_string for anything user-facing: it never fails on bad syntax and its operator set can be restricted. Reserve query_string, which parses full Lucene syntax and returns an error on malformed input, for trusted power users.
solid answer
~50 sBoth parse a mini query language out of a single string, but they differ in how they fail and how much power they hand over. `query_string` supports the full Lucene syntax — `field:value`, `AND`/`OR`/`NOT`, `+`/`-`, wildcards, regular expressions, ranges, `~` for fuzziness and proximity, `^` for boosts — and it **throws a parse error** on malformed input. An unbalanced quote or a stray bracket from a user turns into a 400. It also lets the user aim at fields you never intended to expose and run expensive constructs like a leading wildcard or a regexp. `simple_query_string` uses a smaller operator set (`+`, `|`, `-`, `"`, `*`, `()`, `~`), **never throws** — invalid portions are simply ignored — and its `flags` parameter lets you enable only the operators you want. For a public search box the safest answer is usually neither: build the query yourself from `match`/`multi_match`, and use `simple_query_string` when users genuinely need operators.
code
json · 10 lines{
"query": {
"simple_query_string": {
"query": "\"wireless router\" + dual-band -refurbished",
"fields": ["title^3", "description"],
"flags": "OR|AND|PHRASE",
"default_operator": "and"
}
}
}go deeper
Know that both parse operators out of one string, and that one of them errors on malformed input while the other quietly ignores it.
Compare the operator sets, name the flags parameter that restricts simple_query_string, and explain why a parse error is unacceptable in a public search path.
Frame it as a safety and cost decision: which fields a user can reach, which constructs are expensive, and why hand-built match or multi_match queries are usually the right answer for a consumer search box.
Own the query-surface policy — what operator power different user classes get, how field exposure is governed alongside field-level security, and how expensive-query protections are enforced across every search endpoint.
## Two parsers, one string `query_string` and `simple_query_string` both take a single string containing operators and turn it into a query. They exist because sometimes you want users — or an internal tool — to express more than "these words". The interview question is almost never "what syntax do they support"; it is "which one would you put behind a public search box, and why". ## query_string `query_string` exposes the full Lucene query syntax: - field selection: `status:active`, `title:(quick OR brown)` - boolean operators: `AND`, `OR`, `NOT`, and the `+` / `-` prefixes - wildcards `*` and `?`, and regular expressions between slashes - ranges: `[1 TO 5]`, `{2020-01-01 TO *}` - fuzziness `term~`, proximity `"a b"~5`, boosts `term^3`, grouping with parentheses Useful parameters include `fields` (or `default_field`, which falls back to the `index.query.default_field` index setting, itself defaulting to `*`), `default_operator` (`OR`), `type` (the same family of types as `multi_match`, defaulting to `best_fields`), `allow_leading_wildcard`, `analyze_wildcard`, `phrase_slop`, `fuzzy_max_expansions` and `lenient`. The defining property is strictness: **invalid syntax is an error**. A user typing `wi-fi router (`, or a search box that forwards whatever was typed, produces a 400 rather than results. Applications end up wrapping the call in a try/catch and re-running an escaped version — an admission that the wrong tool was chosen. ## simple_query_string `simple_query_string` was designed for user input. Its syntax is deliberately small: - `+` signifies AND, `|` signifies OR, `-` negates - `"` wraps a phrase, `*` at the end of a term is a prefix - `(` and `)` group, `~N` after a word means fuzziness, `~N` after a phrase means slop Note that the words `AND` and `OR` are not operators here; they are just terms. The key behaviour is that **it never throws**: unmatched quotes and misplaced operators are discarded and the rest of the string still runs. The `flags` parameter (for example `"OR|AND|PREFIX"`, or `"ALL"`, or `"NONE"`) enables only the operator subset you are willing to support, so you can offer quoted phrases while forbidding prefix wildcards. It also accepts `fields`, `default_operator`, `minimum_should_match`, `analyze_wildcard`, `quote_field_suffix` and `lenient`. ## Why this is a security and cost question Exposing `query_string` on a public endpoint hands users two things you probably did not intend to give away. First, **field targeting**. Anyone can write `internal_notes:*` or `owner_email:*@example.com` and probe fields that the UI never shows. Field-level access is not something the query language enforces for you; if a field is in the index and reachable through `default_field: "*"`, it is searchable. The mitigation is an explicit `fields` list, or document-level and field-level security if the licence provides it — never trust the query string to stay in its lane. Second, **cost**. A leading wildcard (`*abc`) or a pathological regular expression forces enormous term enumeration; a wide `default_field: "*"` expands the query across every field in the mapping and can run into the boolean max-clause limit; a big `~2` fuzzy on a short term multiplies term lookups. These are cheap to type and expensive to run, which is a denial-of-service shape. `allow_leading_wildcard: false` and a narrow `fields` list are the first mitigations; a search-thread-pool queue that keeps filling up is how you find out you skipped them. ## The recommendation For an ordinary consumer search box, do not parse operators at all — send the raw string to a `match` or `multi_match` you control, where you decide the fields, boosts, `minimum_should_match` and fuzziness. When users genuinely want operators (support tools, log search, document repositories), use `simple_query_string` with an explicit `fields` list and a restrictive `flags` value. Reserve `query_string` for trusted, authenticated power users and internal tooling — which is exactly the context Kibana's query bar operates in — and even there, set `allow_leading_wildcard: false` and enumerate the fields. ## Traps Candidates often claim `simple_query_string` "escapes" bad syntax; it does not escape, it ignores. Others assume `query_string` bypasses analysis — it does not: ordinary terms are analyzed as usual, though wildcard terms are not analyzed unless `analyze_wildcard` is enabled. And some assume `lenient: true` makes `query_string` safe for user input; `lenient` suppresses format errors such as text against a numeric field, not parse errors from broken syntax.
- How would you stop users reaching fields the UI never exposes through one of these queries?Give an explicit `fields` list instead of relying on `default_field`, which falls back to an index setting that defaults to all fields. Build the field list server-side from the current user's entitlements rather than accepting it from the client, and where the licence allows it, back it with field-level and document-level security so the guarantee does not depend on query construction alone.
- Which constructs in query_string are expensive enough to worry about?Leading wildcards and regular expressions, because they force wide term enumeration rather than a direct dictionary lookup; queries expanded across every field by a wildcard default_field, which can hit the boolean max-clause limit; and generous fuzziness on short terms, which multiplies lookups. Disable leading wildcards, enumerate fields, and cap fuzzy expansions before these reach a public endpoint.
- Does setting lenient to true make query_string safe for arbitrary user input?No. `lenient` suppresses format-related failures, such as a text value being compared against a numeric field, so those clauses are ignored instead of erroring. It does nothing about parse errors from unbalanced quotes or misplaced operators, and nothing about field targeting or expensive wildcards. The safety difference lies in simple_query_string's parser, not in this flag.
saying these in an interview costs you the question
- Says simple_query_string escapes invalid syntax rather than ignoring it
- Claims query_string skips analysis of ordinary terms
- Thinks lenient makes query_string safe for public input
- Exposes query_string on a public box and calls it a feature
- Believes AND and OR are keywords in simple_query_string