Wire PPL where command through the analytics-engine path - #21502
Conversation
PR Code Analyzer ❗AI-powered 'Code-Diff-Analyzer' found issues on commit c49e765.
The table above displays the top 10 most important findings. Pull Requests Author(s): Please update your Pull Request according to the report above. Repository Maintainer(s): You can Thanks. |
PR Reviewer Guide 🔍(Review updated until commit 5f82f72)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to 5f82f72 Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit b0a1006
Suggestions up to commit c49e765
|
|
❌ Gradle check result for c49e765: 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? |
|
Persistent review updated to latest commit b0a1006 |
|
❌ Gradle check result for b0a1006: 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? |
Three orthogonal compatibility gaps surface when CalciteWhereCommandIT runs
through the analytics-engine route. Address them in the DataFusion backend:
1. CAST as a project capability. ReduceExpressionsRule.ProjectReduceExpressionsRule
constant-folds field references through equality filters into typed
literals — `where str0 = 'FURNITURE' | fields str0` becomes
`Project[CAST('FURNITURE' AS VARCHAR)]`. Without CAST in
STANDARD_PROJECT_OPS, OpenSearchProjectRule throws "No backend supports
scalar function [CAST]". 5 where-command tests previously broken;
substrait isthmus and DataFusion handle CAST natively.
2. Comparison ops as project capabilities. PPL `eval x = (a == b)`
produces a LogicalProject whose projected expression is the comparison
itself (returning boolean). EQUALS/NOT_EQUALS/GT/GE/LT/LE were declared
filter-only; add them to STANDARD_PROJECT_OPS so projections of boolean
expressions are accepted. Fixes testDoubleEqualInEvalCommand.
3. ILIKE adapter. Substrait isthmus only knows the standard SQL LIKE
operator; the Calcite-specific ILIKE has no extension. PPL emits ILIKE
for the `contains` operator and for `LIKE` when
plugins.ppl.syntax.legacy.preferred is true (its default), affecting
six where-command tests with "Unable to convert call ILIKE(...)".
Additionally, PPLFuncImpTable always passes an explicit '\\' escape
literal of type CHAR(1), which substrait's like signature rejects as
"Unable to convert call LIKE(string?, char<N>, char<1>)".
The new IlikeFunctionAdapter handles both: ILIKE rewrites to
LIKE(LOWER(field), LOWER(pattern)) — wildcards and the escape character
survive Character.toLowerCase unchanged, preserving case-insensitive
semantics — and the 3-arg form is reduced to 2-arg by dropping the
default-only escape, since PPL never emits a non-default escape (the
contains operator pre-escapes user-provided literals before composing
the wildcard pattern). Both LOWER and 2-arg LIKE are natively supported
by DataFusion.
Registered for ScalarFunction.LIKE because Calcite's SqlLibraryOperators.ILIKE
shares SqlKind.LIKE with the standard LIKE operator and resolves to the
same adapter slot; the adapter checks the operator name to discriminate.
Signed-off-by: Kai Huang <ahkcs@amazon.com>
Self-contained REST integration test under sandbox/qa/analytics-engine-rest mirroring the surface exercised by CalciteWhereCommandIT in the SQL plugin, adapted to the calcs dataset already shipped under src/test/resources/datasets/calcs/. Each test posts a PPL query through POST /_analytics/ppl (exposed by the test-ppl-frontend plugin), exercising the same UnifiedQueryPlanner → CalciteRelNodeVisitor → analytics-engine planner → Substrait → DataFusion pipeline as the SQL plugin's force-routed analytics path. CI for OpenSearch core can verify the where command end-to-end without checking out the SQL plugin or relying on its IT classpath. Coverage (26 cases, all passing): - Comparison operators (=, ==, !=, <, >, <=, >=) - Boolean connectives AND, OR, NOT - IS NULL / IS NOT NULL via isnull() / isnotnull() - IN / NOT IN against keyword and numeric columns - LIKE function and operator (with % and _ wildcards) - contains (lowers to ILIKE — case-insensitive) - Sub-expression scalar calls inside predicates: length, abs, + Signed-off-by: Kai Huang <ahkcs@amazon.com>
b0a1006 to
5f82f72
Compare
|
Persistent review updated to latest commit 5f82f72 |
|
❌ Gradle check result for 5f82f72: null 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? |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #21502 +/- ##
============================================
+ Coverage 73.38% 73.46% +0.07%
- Complexity 74380 74431 +51
============================================
Files 5970 5970
Lines 338267 338267
Branches 48753 48753
============================================
+ Hits 248228 248498 +270
+ Misses 70237 69912 -325
- Partials 19802 19857 +55 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…project#21502) * Wire DataFusion backend for the PPL where command Three orthogonal compatibility gaps surface when CalciteWhereCommandIT runs through the analytics-engine route. Address them in the DataFusion backend: 1. CAST as a project capability. ReduceExpressionsRule.ProjectReduceExpressionsRule constant-folds field references through equality filters into typed literals — `where str0 = 'FURNITURE' | fields str0` becomes `Project[CAST('FURNITURE' AS VARCHAR)]`. Without CAST in STANDARD_PROJECT_OPS, OpenSearchProjectRule throws "No backend supports scalar function [CAST]". 5 where-command tests previously broken; substrait isthmus and DataFusion handle CAST natively. 2. Comparison ops as project capabilities. PPL `eval x = (a == b)` produces a LogicalProject whose projected expression is the comparison itself (returning boolean). EQUALS/NOT_EQUALS/GT/GE/LT/LE were declared filter-only; add them to STANDARD_PROJECT_OPS so projections of boolean expressions are accepted. Fixes testDoubleEqualInEvalCommand. 3. ILIKE adapter. Substrait isthmus only knows the standard SQL LIKE operator; the Calcite-specific ILIKE has no extension. PPL emits ILIKE for the `contains` operator and for `LIKE` when plugins.ppl.syntax.legacy.preferred is true (its default), affecting six where-command tests with "Unable to convert call ILIKE(...)". Additionally, PPLFuncImpTable always passes an explicit '\\' escape literal of type CHAR(1), which substrait's like signature rejects as "Unable to convert call LIKE(string?, char<N>, char<1>)". The new IlikeFunctionAdapter handles both: ILIKE rewrites to LIKE(LOWER(field), LOWER(pattern)) — wildcards and the escape character survive Character.toLowerCase unchanged, preserving case-insensitive semantics — and the 3-arg form is reduced to 2-arg by dropping the default-only escape, since PPL never emits a non-default escape (the contains operator pre-escapes user-provided literals before composing the wildcard pattern). Both LOWER and 2-arg LIKE are natively supported by DataFusion. Registered for ScalarFunction.LIKE because Calcite's SqlLibraryOperators.ILIKE shares SqlKind.LIKE with the standard LIKE operator and resolves to the same adapter slot; the adapter checks the operator name to discriminate. Signed-off-by: Kai Huang <ahkcs@amazon.com> * Add WhereCommandIT QA test for the analytics-engine route Self-contained REST integration test under sandbox/qa/analytics-engine-rest mirroring the surface exercised by CalciteWhereCommandIT in the SQL plugin, adapted to the calcs dataset already shipped under src/test/resources/datasets/calcs/. Each test posts a PPL query through POST /_analytics/ppl (exposed by the test-ppl-frontend plugin), exercising the same UnifiedQueryPlanner → CalciteRelNodeVisitor → analytics-engine planner → Substrait → DataFusion pipeline as the SQL plugin's force-routed analytics path. CI for OpenSearch core can verify the where command end-to-end without checking out the SQL plugin or relying on its IT classpath. Coverage (26 cases, all passing): - Comparison operators (=, ==, !=, <, >, <=, >=) - Boolean connectives AND, OR, NOT - IS NULL / IS NOT NULL via isnull() / isnotnull() - IN / NOT IN against keyword and numeric columns - LIKE function and operator (with % and _ wildcards) - contains (lowers to ILIKE — case-insensitive) - Sub-expression scalar calls inside predicates: length, abs, + Signed-off-by: Kai Huang <ahkcs@amazon.com> --------- Signed-off-by: Kai Huang <ahkcs@amazon.com>
…project#21502) * Wire DataFusion backend for the PPL where command Three orthogonal compatibility gaps surface when CalciteWhereCommandIT runs through the analytics-engine route. Address them in the DataFusion backend: 1. CAST as a project capability. ReduceExpressionsRule.ProjectReduceExpressionsRule constant-folds field references through equality filters into typed literals — `where str0 = 'FURNITURE' | fields str0` becomes `Project[CAST('FURNITURE' AS VARCHAR)]`. Without CAST in STANDARD_PROJECT_OPS, OpenSearchProjectRule throws "No backend supports scalar function [CAST]". 5 where-command tests previously broken; substrait isthmus and DataFusion handle CAST natively. 2. Comparison ops as project capabilities. PPL `eval x = (a == b)` produces a LogicalProject whose projected expression is the comparison itself (returning boolean). EQUALS/NOT_EQUALS/GT/GE/LT/LE were declared filter-only; add them to STANDARD_PROJECT_OPS so projections of boolean expressions are accepted. Fixes testDoubleEqualInEvalCommand. 3. ILIKE adapter. Substrait isthmus only knows the standard SQL LIKE operator; the Calcite-specific ILIKE has no extension. PPL emits ILIKE for the `contains` operator and for `LIKE` when plugins.ppl.syntax.legacy.preferred is true (its default), affecting six where-command tests with "Unable to convert call ILIKE(...)". Additionally, PPLFuncImpTable always passes an explicit '\\' escape literal of type CHAR(1), which substrait's like signature rejects as "Unable to convert call LIKE(string?, char<N>, char<1>)". The new IlikeFunctionAdapter handles both: ILIKE rewrites to LIKE(LOWER(field), LOWER(pattern)) — wildcards and the escape character survive Character.toLowerCase unchanged, preserving case-insensitive semantics — and the 3-arg form is reduced to 2-arg by dropping the default-only escape, since PPL never emits a non-default escape (the contains operator pre-escapes user-provided literals before composing the wildcard pattern). Both LOWER and 2-arg LIKE are natively supported by DataFusion. Registered for ScalarFunction.LIKE because Calcite's SqlLibraryOperators.ILIKE shares SqlKind.LIKE with the standard LIKE operator and resolves to the same adapter slot; the adapter checks the operator name to discriminate. Signed-off-by: Kai Huang <ahkcs@amazon.com> * Add WhereCommandIT QA test for the analytics-engine route Self-contained REST integration test under sandbox/qa/analytics-engine-rest mirroring the surface exercised by CalciteWhereCommandIT in the SQL plugin, adapted to the calcs dataset already shipped under src/test/resources/datasets/calcs/. Each test posts a PPL query through POST /_analytics/ppl (exposed by the test-ppl-frontend plugin), exercising the same UnifiedQueryPlanner → CalciteRelNodeVisitor → analytics-engine planner → Substrait → DataFusion pipeline as the SQL plugin's force-routed analytics path. CI for OpenSearch core can verify the where command end-to-end without checking out the SQL plugin or relying on its IT classpath. Coverage (26 cases, all passing): - Comparison operators (=, ==, !=, <, >, <=, >=) - Boolean connectives AND, OR, NOT - IS NULL / IS NOT NULL via isnull() / isnotnull() - IN / NOT IN against keyword and numeric columns - LIKE function and operator (with % and _ wildcards) - contains (lowers to ILIKE — case-insensitive) - Sub-expression scalar calls inside predicates: length, abs, + Signed-off-by: Kai Huang <ahkcs@amazon.com> --------- Signed-off-by: Kai Huang <ahkcs@amazon.com>
Description
Drives the analytics-engine route to parity for the PPL
wherecommand. Same shape as the fillnull walkthrough (#21472): planner fix, backend capability adds, QA-side IT.Failure modes addressed
Each commit corresponds to a distinct throw site observed when running
CalciteWhereCommandITagainst a force-routed analytics-engine cluster.OpenSearchFilterRule.resolveViableBackends→Unrecognized filter operator [SEARCH]SEARCH(col, sarg)to OR/AND/EQUALS viaRexUtil.expandSearchbefore annotation. Triggered by every multi-valueIN/ chained equality onceReduceExpressionsRule(inPlannerImpl) drivesRexSimplify.OpenSearchProjectRule.annotateExpr→No backend supports scalar function [CAST]ScalarFunction.CASTtoSTANDARD_PROJECT_OPS.ReduceExpressionsRule.ProjectReduceExpressionsRuleconstant-folds field refs through equality filters into typed literals —where str0='FURNITURE' | fields str0becomesProject[CAST('FURNITURE' AS VARCHAR)].OpenSearchProjectRule.annotateExpr→No backend supports scalar function [EQUALS]EQUALS,NOT_EQUALS,GT/GE/LT/LE) toSTANDARD_PROJECT_OPS. PPLeval x = (a == b)projects the comparison itself as a boolean column.Unable to convert call ILIKE(string?, char<N>, char<1>)IlikeFunctionAdapterrewritingILIKE(field, pattern)→LIKE(LOWER(field), LOWER(pattern)). PPL emits ILIKE forcontainsand forLIKEwhenplugins.ppl.syntax.legacy.preferred=true(its default). BothLOWERand 2-argLIKEare native to DataFusion.Unable to convert call LIKE(string?, char<N>, char<1>)'\\'escape literal (always emitted byPPLFuncImpTable, typeCHAR(1), mismatches substrait'slikesignature). PPL never uses a non-default escape — thecontainsoperator pre-escapes user-provided literals before composing the wildcard pattern.Test outcome
SQL plugin —
CalciteWhereCommandITvia:integ-test:analyticsCompatibilityTest(withtests.analytics.force_routing=trueandtests.analytics.parquet_indices=true):Going from
0/39 → 29/39. All 10 remaining failures are command-orthogonal infrastructure gaps — they show up identically on any other PPL command that touches metadata fields, nested fields, full-text predicates, or date-part shorthands:OpenSearchSchemaBuilder→Field [_id] not foundtestWhereWithMetadataFields,testWhereWithMetadataFields2OpenSearchSchemaBuilder→Field [<dotted.path>] not foundtestFilterOnComputedNestedFields,testFilterOnNestedAndRootFields,testFilterOnNestedFields,testFilterOnMultipleCascadedNestedFields,testScriptFilterOnDifferentNestedHierarchyShouldThrow,testAggFilterOnNestedFieldsOpenSearchFilterRule.resolveViableBackends→Constant predicate with no field references reached the filter rule: [query_string(...)]testWhereEquivalentSortCommandUnable to convert call MONTH(precision_timestamp<...>?)testFilterScriptPushDownWithPPLBuiltInFunctionThe MONTH gap follows the bucket-2 ILIKE pattern (rewrite to
EXTRACT(MONTH FROM ts)) but theanalytics-backend-datafusionplugin's compile classpath does not currently includeorg.apache.calcite.avatica.util.TimeUnitRange, which the EXTRACT operator's first operand requires. Will land separately once the classpath/dependency change is sorted.The metadata-field, nested-field, and
query_stringfailures are schema/planner gaps that span many PPL commands and are out of scope for a single function PR.OpenSearch core —
WhereCommandITundersandbox/qa/analytics-engine-rest, hittingPOST /_analytics/pplagainst a parquet-backedcalcsindex:Covers comparisons (
=,==,!=,<,>,<=,>=), boolean connectives (AND,OR,NOT),IS [NOT] NULLviaisnull/isnotnull,IN/NOT INagainst keyword and numeric columns,LIKEfunction and operator with%/_wildcards,contains(ILIKE), and inner scalar calls inside predicates (length,abs, arithmetic+).This is the long-term verification surface: future where-command coverage lands here, and the SQL-plugin IT becomes the v2-path baseline.
Local validation
Pattern for future where-command additions
Bucket-2 / S1 adapter pattern: subsequent substrait-conversion gaps (e.g. MONTH/YEAR, additional library functions) follow the same
ScalarFunctionAdaptershape introduced here. Bucket-1 / S0 capability adds (new functions DataFusion handles natively) are one-line additions toSTANDARD_PROJECT_OPS/STANDARD_FILTER_OPS.Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.