dengc367 commented on issue #14308:
URL: https://github.com/apache/gravitino/issues/14308#issuecomment-6513509571
## Contract update: plan, don't compile
Following the discussion above — and specifically the open question "Should
the response carry
SQL text, a structured relational plan, or both?" — I've settled the
contract for this feature:
**Gravitino resolves a semantic query into a dialect-neutral logical plan;
the engine materializes
it. The server never emits SQL.**
Consumers that already own a planner keep owning the dialect matrix, and
stop re-implementing model
resolution and join-path logic. This supersedes the SQL-text sketch in the
proposal above and in
#14332.
### Shape
Request: semantic only, no dialect.
```json
{
"metrics": ["Gross_Revenue"],
"dimensions": ["Region_Name", "Calendar_Month"],
"filters": [{"field": "Calendar_Month", "operator": "EQ", "value":
"2026-10"}],
"limit": 1000
}
```
Response: `{"code": 0, "plan": {...}}` with `sources`, `joins`,
`selections`, `filters`, `groupBy`,
`limit`, `warnings`, and the `semanticModelVersion` the plan was resolved
against. No `sql`, no
dialect, no aliases, no quoting, no literal syntax.
The constraint that shaped this: Ossie expressions are **per-dialect SQL
text**
(`Expression -> DialectExpression[]`), so a fully structured AST would force
Gravitino to own a SQL
parser per dialect — a larger liability than the renderer being removed. The
relational layer is
fully neutral; the expression layer carries the model's dialect map and lets
the consumer pick.
Materialization is an SPI: `SemanticQueryPlanConverter<T>` in `api`. It is
generic so a Trino
converter can return a `LogicalPlan`, a Spark converter SQL text, and an
Ossie consumer its own
nodes.
### Decisions
| # | Question | Decision |
| --- | --- | --- |
| 1 | Version pinning | The plan carries `semanticModelVersion` (drift
detection; historical-version planning and a `409` mismatch are follow-ups) |
| 2 | Physical sources | Expose `NameIdentifier` sources, so a JDBC-only
consumer can render SQL without a Gravitino connection |
| 3 | `limit` type | `long` |
| 4 | Filter operators | `EQ/NE/GT/GE/LT/LE` only; `IN`/`LIKE` wait for
nullability metadata |
| 5 | Dimension-only queries | Detail rows, no implicit `DISTINCT` |
| 6 | Naming | `SemanticQueryPlan` and `POST .../plan` |
| 7 | Converter location | `api` module, so engine plugins don't pull
`client-java` |
| 8 | Response envelope | Plan nested under `plan`, leaving room for a
future optional `materializedSql` |
What this removes from the prototype: `SemanticQuery.dialect`,
`SemanticQueryPlan.sql`, the
pluggable planner SPI plus `gravitino.semanticModel.queryPlanner` and its
`501` path, and the
in-server Spark renderer, which becomes a reference converter in a library
module.
### Prerequisite
The plan carries the version of the definition it was resolved against, but
`SemanticModel` does
not expose it today even though the storage layer already versions every
model. Exposing the
current committed version on the loaded model is part of the change.
The full contract — API signatures, JSON examples, deterministic resolution
rules and the error
matrix — is in [the design
doc](https://github.com/dengc367/gravitino/blob/dc1397478dee242bae743d5b3c088c1df42eef2c/design-docs/gravitino-semantic-query-plan-contract.md).
I will send the reshaping as a follow-up PR and link it here. Unless there
are objections, that PR
will implement this shape.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]