mchades commented on code in PR #14378:
URL: https://github.com/apache/gravitino/pull/14378#discussion_r4438368551


##########
design-docs/gravitino-semantic-model-source-lookup-design.md:
##########
@@ -0,0 +1,484 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+# Design of Semantic Model Dataset Lookup by Source in Gravitino
+
+## Background
+
+A Semantic Model dataset references a table or logical View through 
`Dataset.source`. Sources may
+belong to another catalog or schema in the same metalake. Users browsing a 
source cannot currently
+list its associated Semantic Models without collecting and inspecting model 
definitions themselves.
+
+Gravitino should provide this lookup through its existing object relationship 
API pattern. The
+result helps users and agents discover models built from a source and identify 
the datasets to
+inspect when that source changes.
+
+## Goals
+
+1. **Discovery.** List fully qualified identifiers of Semantic Model datasets 
directly associated
+   with a table or View through REST, Java, and Python, across catalogs and 
schemas in the same
+   metalake.
+2. **Visibility.** Require access to the source metadata and return datasets 
only from models the
+   caller can load.
+3. **Consistency.** Maintain source associations in the same transaction as 
model definition writes.
+4. **Integration.** Follow existing object relationship APIs, client 
capability interfaces, and
+   listener and audit conventions.
+
+## Non-Goals
+
+1. Transitive View dependencies, column or metric impact analysis, and 
validation of whether a
+   model can currently compile or execute. These checks require additional 
lineage or compiler
+   analysis beyond the source references explicitly declared by datasets.
+2. Automatically changing model definitions, blocking source changes because 
models reference the
+   source, detecting mismatches between model references and current sources, 
and sending
+   notifications. These need separate decisions about detecting source 
changes, permissions to
+   modify affected models, and handling update or notification failures.
+3. Independent association management, exposing internal source IDs, and 
historical association
+   queries. Associations are derived from model definitions and updated when 
those definitions are
+   written. Editing associations separately could make them disagree with the 
definitions. Discovery
+   of current datasets needs neither exposed source IDs nor retained 
association history.
+4. Stable dataset IDs, dataset-specific privileges, and independent dataset 
lifecycle APIs. Dataset
+   identifiers locate datasets in the current model definition. Tracking the 
same dataset across
+   model versions or authorizing it separately requires rules for dataset 
identity and lifecycle.
+
+## Proposal
+
+### Association Contract
+
+Each dataset has one association to the registered Gravitino source ID and 
type resolved during the
+latest successful model definition write (create, import, overwrite, or 
replacement). The model ID
+and exact dataset name identify which dataset an association belongs to. Only 
tables or Views named
+in `Dataset.source` are indexed; lookup does not follow the dependencies of a 
referenced View.
+
+`Dataset.name` is a case-sensitive alias unique within the model and need not 
match the table or
+View name in `Dataset.source`.
+
+Definition updates and association updates must commit in the same 
transaction. Each association's
+`dataset_name` must match the corresponding `Dataset.name` in that committed 
definition.
+
+Lookup returns one identifier per matching dataset whose model has not been 
deleted and can be
+loaded by the caller. For example, model 
`analytics.semantic.employee_analysis` in metalake `example`
+has two datasets referencing the same source:
+
+| Model               | Dataset    | Source                |
+| ------------------- | ---------- | --------------------- |
+| `employee_analysis` | `employee` | `hr.public.employees` |
+| `employee_analysis` | `manager`  | `hr.public.employees` |
+
+Storing this model creates two association rows; looking up 
`hr.public.employees` returns both
+dataset identifiers. Callers needing only models derive the containing model 
identifiers and remove
+duplicates. Updates follow [Lifecycle Behavior](#lifecycle-behavior); drift 
and other constraints
+are covered under [Known Limitations](#known-limitations).
+
+### API Contract
+
+#### Java API
+
+Add a read-only capability in the semantic API package:
+
+```java
+/** Lists Semantic Model datasets associated with a source metadata object. */
+public interface SupportsSemanticModels {
+
+  /**
+   * Lists datasets directly associated with this source from visible Semantic 
Models.
+   *
+   * @return The fully qualified dataset identifiers, or an empty array.
+   * @throws NoSuchMetadataObjectException If the source does not exist.
+   */
+  NameIdentifier[] listSemanticModelDatasets() throws 
NoSuchMetadataObjectException;
+}
+```
+
+Each result has five levels in total: namespace `[metalake, catalog, schema, 
semanticModel]` and the
+exact dataset name as `name`, following the existing metric identifier 
convention. This identifies
+a member of the current model definition and does not create a separate 
dataset metadata object.
+
+Construct identifiers from components with `NameIdentifier.of(namespace, 
datasetName)` and preserve
+the structured `namespace` and `name` during serialization. Dataset names may 
contain literal dots.
+Joining components with `.` and splitting that string again would treat dots 
in dataset names as
+namespace separators.
+
+`Table` and `View` add the following default capability accessor, following 
`supportsTags()`:
+
+```java
+/**
+ * Returns the Semantic Model dataset lookup operations for this source.
+ *
+ * @return The Semantic Model dataset lookup operations.
+ * @throws UnsupportedOperationException If the implementation does not 
support lookup.
+ */
+default SupportsSemanticModels supportsSemanticModels() {
+  throw new UnsupportedOperationException("Semantic Model dataset lookup is 
not supported");
+}
+```
+
+The Gravitino Java client's table and View implementations provide this 
capability through shared
+object relationship request handling. Underlying catalog connectors do not 
implement the lookup.
+
+```java
+NameIdentifier[] datasets = 
table.supportsSemanticModels().listSemanticModelDatasets();
+```
+
+Results can belong to a different catalog from the source. Java and Python 
therefore return the same
+fully qualified five-level identifiers as REST, including metalake and catalog 
in the namespace.
+For a result `dataset`, `NameIdentifier.of(dataset.namespace().levels())` 
gives its containing model
+identifier. Remove duplicates from these model identifiers to obtain the 
associated model list.
+
+#### REST API
+
+Add a route alongside the existing object tag and policy routes:
+
+```http
+GET /api/metalakes/{metalake}/objects/{type}/{fullName}/semantic-model-datasets
+```
+
+`type` accepts `table` or `view`. `fullName` contains the source's catalog, 
schema, and name using the
+existing `MetadataObject` format, such as `hr.public.employees`, with normal 
URL path encoding.
+Limits on names containing literal dots are described under [Known 
Limitations](#known-limitations).
+
+The endpoint implements `listSemanticModelDatasets` and always returns the 
existing
+`EntityListResponse`, with one identifier per matching dataset. For the 
employee example above:
+
+```json
+{
+  "code": 0,
+  "identifiers": [
+    {
+      "namespace": ["example", "analytics", "semantic", "employee_analysis"],
+      "name": "employee"
+    },
+    {
+      "namespace": ["example", "analytics", "semantic", "employee_analysis"],
+      "name": "manager"
+    }
+  ]
+}
+```
+
+- **Uniqueness and ordering.** Return each dataset identifier once. Sort 
lexicographically by the
+  model namespace components (`metalake`, `catalog`, `schema`, 
`semanticModel`), then by the
+  case-sensitive dataset name. This order is independent of dataset order in 
the definition.
+  Compare every component case-sensitively by UTF-16 code units (Java 
`String.compareTo` order),
+  independent of locale and database collation.
+- **Empty results.** Return `identifiers: []` when the source exists but no 
matching datasets are
+  visible.
+- **Errors.** Unsupported source types return `400`. Missing or inaccessible 
sources follow the
+  existing object relationship API error behavior, rather than becoming empty 
successful results.
+  Storage and source lookup failures fail the request without partial results.
+
+The response contains identifiers only. Callers select the result's catalog 
and use the existing
+model load API to inspect the containing model and its datasets. No internal 
IDs, validity status,
+hidden-model counts, or association mutation APIs are added.
+
+#### Python API
+
+The Python table and View APIs add `supports_semantic_models()`, returning a 
capability with
+`list_semantic_model_datasets() -> list[NameIdentifier]`. It uses the same 
REST endpoint and full
+four-level namespace plus dataset name as Java. Java and Python clients 
preserve identifier
+components and server ordering and do not scan catalogs or load all models to 
perform lookup.
+
+### Authorization
+
+- **Source access.** The REST entry point uses `CAN_ACCESS_METADATA` for the 
source, as existing
+  object relationship APIs do. Source type, name normalization, existence 
checks, and internal ID
+  resolution reuse the existing table and View paths. Source existence is 
still checked when
+  authorization is disabled.
+- **Model visibility.** For each distinct candidate model, apply
+  `LOAD_SEMANTIC_MODEL_AUTHORIZATION_EXPRESSION` in the caller's context using 
the containing model
+  identifier, not the dataset identifier. Include or exclude all matching 
datasets from that model
+  together. Apply this filtering in REST before constructing the response.
+- **Catalog and schema access.** Apply the model load rules for ownership and 
use or modify
+  privileges, including access to that model's catalog and schema. Schema 
listing checks the schema
+  named in its request before filtering models. This lookup can return models 
from several schemas
+  and catalogs, so it must check each model's own parents using the full load 
expression.
+- **Failure handling.** Reuse `MetadataAuthzHelper.filterByExpression`: 
exclude a model if its
+  authorization check denies access or throws an exception, and log evaluation 
exceptions. If the

Review Comment:
   Added a Known Limitations note describing successful incomplete or empty 
responses with no failure or retry indication, and explicitly stating that this 
follows existing list and relationship API authorization filtering. I don't 
think a separate tracking issue is needed for this proposal. If you'd like to 
change the shared behavior, please open an issue for discussion.



##########
design-docs/gravitino-semantic-model-source-lookup-design.md:
##########
@@ -0,0 +1,484 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+# Design of Semantic Model Dataset Lookup by Source in Gravitino
+
+## Background
+
+A Semantic Model dataset references a table or logical View through 
`Dataset.source`. Sources may
+belong to another catalog or schema in the same metalake. Users browsing a 
source cannot currently
+list its associated Semantic Models without collecting and inspecting model 
definitions themselves.
+
+Gravitino should provide this lookup through its existing object relationship 
API pattern. The
+result helps users and agents discover models built from a source and identify 
the datasets to
+inspect when that source changes.
+
+## Goals
+
+1. **Discovery.** List fully qualified identifiers of Semantic Model datasets 
directly associated
+   with a table or View through REST, Java, and Python, across catalogs and 
schemas in the same
+   metalake.
+2. **Visibility.** Require access to the source metadata and return datasets 
only from models the
+   caller can load.
+3. **Consistency.** Maintain source associations in the same transaction as 
model definition writes.
+4. **Integration.** Follow existing object relationship APIs, client 
capability interfaces, and
+   listener and audit conventions.
+
+## Non-Goals
+
+1. Transitive View dependencies, column or metric impact analysis, and 
validation of whether a
+   model can currently compile or execute. These checks require additional 
lineage or compiler
+   analysis beyond the source references explicitly declared by datasets.
+2. Automatically changing model definitions, blocking source changes because 
models reference the
+   source, detecting mismatches between model references and current sources, 
and sending
+   notifications. These need separate decisions about detecting source 
changes, permissions to
+   modify affected models, and handling update or notification failures.
+3. Independent association management, exposing internal source IDs, and 
historical association
+   queries. Associations are derived from model definitions and updated when 
those definitions are
+   written. Editing associations separately could make them disagree with the 
definitions. Discovery
+   of current datasets needs neither exposed source IDs nor retained 
association history.
+4. Stable dataset IDs, dataset-specific privileges, and independent dataset 
lifecycle APIs. Dataset
+   identifiers locate datasets in the current model definition. Tracking the 
same dataset across
+   model versions or authorizing it separately requires rules for dataset 
identity and lifecycle.
+
+## Proposal
+
+### Association Contract
+
+Each dataset has one association to the registered Gravitino source ID and 
type resolved during the
+latest successful model definition write (create, import, overwrite, or 
replacement). The model ID
+and exact dataset name identify which dataset an association belongs to. Only 
tables or Views named
+in `Dataset.source` are indexed; lookup does not follow the dependencies of a 
referenced View.
+
+`Dataset.name` is a case-sensitive alias unique within the model and need not 
match the table or
+View name in `Dataset.source`.
+
+Definition updates and association updates must commit in the same 
transaction. Each association's
+`dataset_name` must match the corresponding `Dataset.name` in that committed 
definition.
+
+Lookup returns one identifier per matching dataset whose model has not been 
deleted and can be
+loaded by the caller. For example, model 
`analytics.semantic.employee_analysis` in metalake `example`
+has two datasets referencing the same source:
+
+| Model               | Dataset    | Source                |
+| ------------------- | ---------- | --------------------- |
+| `employee_analysis` | `employee` | `hr.public.employees` |
+| `employee_analysis` | `manager`  | `hr.public.employees` |
+
+Storing this model creates two association rows; looking up 
`hr.public.employees` returns both
+dataset identifiers. Callers needing only models derive the containing model 
identifiers and remove
+duplicates. Updates follow [Lifecycle Behavior](#lifecycle-behavior); drift 
and other constraints
+are covered under [Known Limitations](#known-limitations).
+
+### API Contract
+
+#### Java API
+
+Add a read-only capability in the semantic API package:
+
+```java
+/** Lists Semantic Model datasets associated with a source metadata object. */
+public interface SupportsSemanticModels {
+
+  /**
+   * Lists datasets directly associated with this source from visible Semantic 
Models.
+   *
+   * @return The fully qualified dataset identifiers, or an empty array.
+   * @throws NoSuchMetadataObjectException If the source does not exist.
+   */
+  NameIdentifier[] listSemanticModelDatasets() throws 
NoSuchMetadataObjectException;
+}
+```
+
+Each result has five levels in total: namespace `[metalake, catalog, schema, 
semanticModel]` and the
+exact dataset name as `name`, following the existing metric identifier 
convention. This identifies
+a member of the current model definition and does not create a separate 
dataset metadata object.
+
+Construct identifiers from components with `NameIdentifier.of(namespace, 
datasetName)` and preserve
+the structured `namespace` and `name` during serialization. Dataset names may 
contain literal dots.
+Joining components with `.` and splitting that string again would treat dots 
in dataset names as
+namespace separators.
+
+`Table` and `View` add the following default capability accessor, following 
`supportsTags()`:
+
+```java
+/**
+ * Returns the Semantic Model dataset lookup operations for this source.
+ *
+ * @return The Semantic Model dataset lookup operations.
+ * @throws UnsupportedOperationException If the implementation does not 
support lookup.
+ */
+default SupportsSemanticModels supportsSemanticModels() {
+  throw new UnsupportedOperationException("Semantic Model dataset lookup is 
not supported");
+}
+```
+
+The Gravitino Java client's table and View implementations provide this 
capability through shared
+object relationship request handling. Underlying catalog connectors do not 
implement the lookup.
+
+```java
+NameIdentifier[] datasets = 
table.supportsSemanticModels().listSemanticModelDatasets();
+```
+
+Results can belong to a different catalog from the source. Java and Python 
therefore return the same
+fully qualified five-level identifiers as REST, including metalake and catalog 
in the namespace.
+For a result `dataset`, `NameIdentifier.of(dataset.namespace().levels())` 
gives its containing model
+identifier. Remove duplicates from these model identifiers to obtain the 
associated model list.
+
+#### REST API
+
+Add a route alongside the existing object tag and policy routes:
+
+```http
+GET /api/metalakes/{metalake}/objects/{type}/{fullName}/semantic-model-datasets
+```
+
+`type` accepts `table` or `view`. `fullName` contains the source's catalog, 
schema, and name using the
+existing `MetadataObject` format, such as `hr.public.employees`, with normal 
URL path encoding.
+Limits on names containing literal dots are described under [Known 
Limitations](#known-limitations).
+
+The endpoint implements `listSemanticModelDatasets` and always returns the 
existing
+`EntityListResponse`, with one identifier per matching dataset. For the 
employee example above:

Review Comment:
   Added a Known Limitations note for unbounded candidate processing, 
authorization and sorting costs, memory use, and response size, consistent with 
existing unpaginated relationship APIs. It links the existing REST pagination 
proposal #14453; pagination and processing bounds remain outside this proposal.



-- 
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]

Reply via email to