Files
58ca68ce96 fix: make max_edit_distance a soft keyword and simplify fuzzy query (#51077)
## Summary

Follow-up polish to #50933 (`text_match_fuzzy`). Three related changes:

### 1. `max_edit_distance` is no longer a reserved keyword (fixes
#51058)
#50933 introduced `max_edit_distance` as a hard ANTLR lexer keyword,
which reserves that word across the *entire* expression language — a
collection with a scalar field literally named `max_edit_distance` would
fail to parse `max_edit_distance > 1` after upgrade.

This makes it a **soft keyword**: the grammar accepts a plain
`Identifier` in the option slot and `VisitTextMatchFuzzy` validates
(case-insensitively) that it is `max_edit_distance`, rejecting any other
name. `text_match_fuzzy` itself stays a reserved *operator* keyword,
like `text_match` / `phrase_match`.

### 2. Simplify the fuzzy OR
`fuzzy_match_query` built its per-token disjunction with
`BooleanQuery::with_minimum_required_clauses(subqueries, 1)` (copied
from the real-`k` `min_should_match` path). The vendored fork's
`BooleanQuery::union(queries)` expresses a plain OR of `Should` clauses
directly — semantically identical, one call, no magic `1`.

### 3. Fast path for `max_edit_distance = 0`
`K = 0` is exactly a term match, but tantivy's `FuzzyTermQuery` has no
`distance == 0` short-circuit — it still builds a Levenshtein automaton
per token. Route `K = 0` to the cheaper `match_query` (multiterms) path.

## Tests
- New `TestExpr_TextMatchFuzzy_SoftKeyword`: a field named
`max_edit_distance` in an ordinary filter parses; case-insensitive
`MAX_EDIT_DISTANCE=` works; a wrong option name is rejected.
- Existing `TestExpr_TextMatchFuzzy` and the full `planparserv2` suite
pass; `cargo check` on the tantivy binding passes.

Design doc updated accordingly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: xiaofanluan <xf@hjjaq.com>
Co-authored-by: xiaofanluan <xf@hjjaq.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 01:36:30 +08:00
..