Added fuzzy query translator and serializer to DSL analytics path - #22645
Added fuzzy query translator and serializer to DSL analytics path#22645ask-kamal-nayan wants to merge 6 commits into
Conversation
Signed-off-by: Kamal Nayan <askkamal@amazon.com>
Signed-off-by: Kamal Nayan <askkamal@amazon.com>
Signed-off-by: Kamal Nayan <askkamal@amazon.com>
Signed-off-by: Kamal Nayan <askkamal@amazon.com>
…ssertions, fix message casing Signed-off-by: Kamal Nayan <askkamal@amazon.com>
Signed-off-by: Kamal Nayan <askkamal@amazon.com>
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Explore these optional code suggestions:
|
|
❌ Gradle check result for bb30c10: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
Description
Adds
FuzzyQueryTranslatorandFuzzySerializerto thedsl-query-executorandanalytics-backend-lucenesandbox plugins, enabling DSLfuzzyqueries to be translated into delegated predicates and pushed down to Lucene for execution.What: A translator that converts
FuzzyQueryBuilderinto aFUZZYRexCall with MAP operands, and a serializer that reconstitutes theFuzzyQueryBuilderon the data node from those operands.Why: Edit-distance matching has no DataFusion equivalent. The fuzzy query must be pushed down to Lucene as a delegated predicate — Lucene builds a Levenshtein automaton that produces a match bitset directly, rather than attempting row-by-row evaluation in the analytics engine.
Where: Two components, both required for end-to-end operation:
FuzzyQueryTranslatorinsandbox/plugins/dsl-query-executor— translates the DSL query builder into a RexCall whose operator name is"FUZZY", which resolves toScalarFunction.FUZZYvia name-based dispatch atScalarFunction.fromSqlOperatorWithFallback().FuzzySerializerinsandbox/plugins/analytics-backend-lucene+ registration inQuerySerializerRegistry— reconstitutes theFuzzyQueryBuilderfrom the RexCall operands so the Lucene backend can execute the fuzzy query at the shard level.Without the translator, the query wraps in
UnresolvedQueryCalland fails atOpenSearchFilterRule. Without the serializer,ScalarFunction.FUZZYresolves but predicate serialization has no handler.Supported Parameters
value(required)fuzzinessAUTOFuzziness.build()+asDistance()to fail fast on invalid values like"abc"prefix_length0max_expansions50transpositionstruerewriteconstant_scoretop_terms_*variants change which documents match even in a non-scoring contextNon-default values are emitted as additional MAP operands at index 2+. Default values are omitted — the serializer lets
FuzzyQueryBuilderapply its own defaults.Fuzziness accepts
"0","1","2","AUTO", and"AUTO:x,y"(custom auto bounds). Values like"3"are accepted and clamped to 2 by Lucene at query time, preserving legacy parity withStringFieldType.fuzzyQuery(StringFieldType.java:103).Rejected Parameters
boostAbstractQueryBuilder.toQuerylines 130–136:BoostQuerywrapping_nameAbstractQueryBuilder.toQuerylines 137–139: named query registrationKnown Divergences from Legacy
_search_searchDelegatedPredicateFunction.java:23-33)MatchNoneQueryBuilder(FuzzyQueryBuilder.doRewriteline 347)ConversionContext.getFieldthrows if field absent from schema (ConversionContext.java:102-107)FuzzyQueryBuildertoString's value before Lucene processing regardlesssearch.allow_expensive_queriesfalse, fuzzy queries are refused at query-build time (StringFieldType.fuzzyQuery:92,KeywordFieldMapper.KeywordFieldType.fuzzyQuery:736); the setting is declared atSearchService.java:221(defaulttrue, dynamic) and delivered as aBooleanSupplierviaQueryShardContext.allowExpensiveQueries()(QueryShardContext.java:373)LuceneAnalyticsBackendPlugin.java:282passes a hardcoded always-true supplier_namehandling across familyterm,terms,range, andfuzzyall reject_namewith aConversionException;prefixandwildcardsilently ignore it (with an explanatory comment)term/terms/range)prefix/wildcardare the outliers that silently drop it. The family should converge on one policy — tracked as cross-cutting work, not resolved here.flat_object/versionfield typesfuzzyQuery())OpenSearchSchemaBuilder.mapFieldType()returnsnullfor these types, excluding them from the Calcite schema entirelyTesting
FuzzyQueryTranslatorTests.javaQuerySerializerRegistryTests.java(additions)fuzzy_default_params.json,fuzzy_all_params.jsonDslQueryIT.java@AwaitsFix)dsl-query-executor/analytics-backend-luceneTranslator tests cover: rejection of non-default boost,
_name, non-VARCHAR fields, unknown fields, invalid fuzziness values (including non-numeric like"abc"), negativeprefix_length, zeromax_expansions, null value, empty-string value; acceptance ofAUTO:4,7custom auto bounds and fuzziness"3"(clamped); correct operator name, field/query operand shape, non-default param emission, and default-param omission.Serializer tests cover: defaults round-trip, custom fuzziness, all-params round-trip, rewrite pass-through, transpositions=false isolation, missing-field error, and unrecognized-param tolerance.
Golden files assert the full Calcite logical plan shape for a fuzzy query with default parameters and with all five optional parameters overridden.
Integration tests (
testFuzzyQueryOnKeywordField,testFuzzyQueryOnTextField) are parked with@AwaitsFixpending the analytics E2E pipeline (fragment conversion + shard execution + Arrow Flight drain), matching sibling ITs for range, prefix, wildcard, and bool queries.Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.