Search
What to know
Query DSL splits into full-text queries (match, match_phrase, multi_match, query_string) and term-level queries (term, terms, range, exists, prefix, wildcard, fuzzy). bool composes them with must, filter, should and must_not; filter and must_not contribute no score and are cacheable. Relevance comes from BM25 by default and can be shaped with boost, function_score, constant_score and rescore. Dates accept math such as "gte": "now-7d/d", and the multi_match types (best_fields, most_fields, cross_fields, phrase_prefix) change how per-field scores combine.
Traps
matchanalyzes its input;termdoes not. Atermquery on an analyzedtextfield rarely matches, and amatchquery on akeywordfield only matches the entire value.minimum_should_matchdefaults to 1 only when there is nomustorfilterclause. Adding amustsilently makesshouldoptional (scoring only).from + sizeis capped byindex.max_result_window(default 10,000). Deep paging needssearch_afterwith a unique tiebreaker sort, or a point-in-time plussearch_after.must_notnever scores, and a bool query containing onlymust_notmatches everything else.- Range queries on
keywordfields compare lexicographically, not numerically or chronologically.
Rule of thumb
Put anything that only filters (status, tenant, date window) in filter, and keep must/should for clauses that should influence ranking - it improves both latency and score stability.