#23030·OpenSearch

[DISCUSS] Fix analytics-engine & SQL plugin integration

Author: mch2Created Sep 14, 2026Updated Sep 18, 2026
Labelsdiscussanalytics-engine

Today the analytics engine accepts a Calcite RelNode from a front-end plugin which the SQL plugin for sql/ppl language support. We've largely made this functional but I think its time to clean up this integration path. Some problems we currently have:

  • Planning is scattered / duplicated - SQL owns the grammar, parsing, building an AST and building the initial Calcite plan, then we run through AEs planner to correct the plan before execution. This leaves us needing to make updates across repos making the feedback loop and development slow, and failure attribution ambiguous
  • In sql plugin, one function table serves two execution targets (AE and legacy/v3 ppl/sql route) with different data representations, with no per-target resolution. This adds risk to sql plugin for existing routes For example, this pr fixes nested fields for AE by adding an ITEM registration to PPLFuncImpTable that special-cases ARRAY<ROW<...>>, which is the shape AE hands Calcite. So a decision about how AE represents nested data is now encoded in the plugin's shared function table. It also isn't gated on the analytics route, so the DSL and v1 paths get the new typing too, untested.
  • Testing is scattered with a circular dependency - AE e2e tests need to spin up full clusters that depend on sql's planning layer, creating a circular dep. Because a front-end has nothing to compile against, the only way to answer "will this query work" is to run it.
  • AE maintains ~160 adapter classes to repair plans as they arrive, so that we can execute. Some of that is legitimate "lowering", meaning converting to Substrait so a DataFusion back-end can execute it. But most are repair work, for example ip is the obvious one. OpenSearch has both an ip and a binary field type and both are VARBINARY to Calcite, so an ip filter arrives as an untyped literal and the engine works out which it was with hacks.

Some options on how we solve this:

  • There is no shared type vocabulary and no agreed set of operations at the API boundary, so the engine takes whatever a front-end produces in the plan and repairs what it cannot execute. AE should make its vocabulary explicit and publish it. by this I mean types, functions etc through SqlOperatorTable. This would require changes to SQL plugin's UnifiedQueryAPI to allow us to inject our own type factory and function table.
  • Rip what we need from sql and create two language front-end plugins (one for sql/ppl) and have them live next to AE. We'd basically take the grammar, AST builders etc from sql plugin. This means we completely decouple from the sql plugin, and evolve our own versions of the languages that would diverge from the current spec. This feels extreme, but we already are heading down this path with the limitations imposed by AE and the subset of the language spec we can support.
  • start a sql only plugin next to AE - translate using existing Unified API boundary to a dialect that the AE owns... have to put more thought into this one but this is largely how sql integrates with spark already.

Still have more thoughts here I need to get on paper, but wanted to start a discussion on this.

Source: opensearch-project/OpenSearch