jerryshao commented on code in PR #14210:
URL: https://github.com/apache/gravitino/pull/14210#discussion_r4421041398


##########
docs/manage-semantic-model-metadata-using-gravitino.md:
##########
@@ -326,6 +327,144 @@ loaded = models.load_semantic_model(ident)
 </TabItem>
 </Tabs>
 
+### Discover Metrics in a Schema
+
+Use schema-level metric discovery to find metrics across the current 
definitions of Semantic
+Models in one schema. You can list identifiers or retrieve complete metric 
definitions without
+first listing and loading each model. These examples use the `total_revenue` 
metric in
+`mart.sales_model` created above, before importing any other models.
+
+#### List Metric Identifiers
+
+<Tabs groupId='language' queryString>
+<TabItem value="shell" label="REST">
+
+```shell
+curl -X GET -H "Accept: application/vnd.gravitino.v1+json" \
+  
'http://localhost:8090/api/metalakes/example/catalogs/sales/schemas/mart/semantic-model-metrics'
+```
+
+The default is `details=false`; only `true` (case-insensitive) enables 
complete metric definitions.
+If `sales_model` is the only model with metrics in this schema, the default 
response is:
+
+```json
+{
+  "code": 0,
+  "identifiers": [
+    {
+      "namespace": ["example", "sales", "mart", "sales_model"],
+      "name": "total_revenue"
+    }
+  ]
+}
+```
+
+</TabItem>
+<TabItem value="java" label="Java">
+
+```java
+NameIdentifier[] metricIdentifiers = models.listMetrics(Namespace.of("mart"));
+```
+
+</TabItem>
+<TabItem value="python" label="Python">
+
+```python
+metric_identifiers = models.list_metrics(Namespace.of("mart"))
+```
+
+</TabItem>
+</Tabs>
+
+Metric names are unique within a model. Two models can both define 
`total_revenue`; use the
+namespace together with the metric name to distinguish them.
+
+| Interface | Namespace in each result | Metric name |
+|-----------|--------------------------|-------------|
+| REST | `["example", "sales", "mart", "sales_model"]` | `total_revenue` |
+| Java / Python, using the loaded `sales` catalog | `["mart", "sales_model"]` 
| `total_revenue` |
+
+The SDK methods accept a schema namespace, such as `Namespace.of("mart")`. Do 
not include the
+metalake, catalog, or model in that argument.
+
+#### Retrieve Metric Definitions
+
+<Tabs groupId='language' queryString>
+<TabItem value="shell" label="REST">
+
+```shell
+curl -X GET -H "Accept: application/vnd.gravitino.v1+json" \
+  
'http://localhost:8090/api/metalakes/example/catalogs/sales/schemas/mart/semantic-model-metrics?details=true'
+```
+
+For the same model, the response is:
+
+```json
+{
+  "code": 0,
+  "metrics": [
+    {
+      "namespace": ["example", "sales", "mart", "sales_model"],
+      "metric": {
+        "name": "total_revenue",
+        "expression": {
+          "dialects": [
+            {"dialect": "ANSI_SQL", "expression": "SUM(orders.order_amount)"}
+          ]
+        },
+        "datatype": "Decimal"
+      }
+    }
+  ]
+}
+```
+
+</TabItem>
+<TabItem value="java" label="Java">
+
+```java
+SemanticModelMetric[] metricInfos = 
models.listMetricInfos(Namespace.of("mart"));
+```
+
+</TabItem>
+<TabItem value="python" label="Python">
+
+```python
+metric_infos = models.list_metric_infos(Namespace.of("mart"))
+```
+
+</TabItem>
+</Tabs>
+
+Each SDK result exposes `namespace()` and `metric()`. The metric contains its 
name, expression,
+and any stored data type, description, AI context, or custom extensions. To 
construct its identifier,
+use `NameIdentifier.of(info.namespace(), info.metric().name())` in Java or
+`NameIdentifier.builder(info.namespace(), info.metric().name())` in Python.
+
+#### Ordering, Visibility, and Updates
+
+Both listing modes sort results by the containing model's identifier and then 
by case-sensitive
+metric name. Models without metrics contribute no entries. If there are no 
visible metrics, REST
+returns an empty `identifiers` or `metrics` array and the SDKs return an empty 
array or list.
+
+With authorization enabled, discovery requires access to the parent catalog 
and schema. It
+includes metrics only from models the caller can discover through 
`USE_SEMANTIC_MODEL`,
+`MODIFY_SEMANTIC_MODEL`, or ownership, as described in
+[Ownership and Privileges](#ownership-and-privileges). Discovery does not 
revalidate access to
+source tables or views and does not grant access to source data.
+
+Discovery reflects each model's current committed definition: renaming a model 
changes the
+namespace returned for its metrics, replacing its definition changes the 
discovered metrics,
+and dropping it removes its metrics from discovery. Manage metric definitions 
through their
+containing Semantic Models; discovery does not provide a separate metric 
lifecycle or execute
+metric expressions.
+
+An empty result is a successful discovery response. Missing schemas, denied 
parent access, and
+unsupported operations are reported as errors. Storage or decoding failures 
fail the request
+instead of returning partial results. See the
+[REST API 
reference](./api/rest/gravitino-rest-api#tag/semantic-model/operation/listSemanticModelMetrics)

Review Comment:
   This would be the first deep Redoc link (`#tag/.../operation/...`) in our 
docs; other pages link only to `./api/rest/gravitino-rest-api`. The tag and 
operationId exist in `semantic-models.yaml`, but could you confirm the anchor 
resolves on the generated website? If not, linking to the page root would be 
safer.



##########
docs/manage-semantic-model-metadata-using-gravitino.md:
##########
@@ -326,6 +327,144 @@ loaded = models.load_semantic_model(ident)
 </TabItem>
 </Tabs>
 
+### Discover Metrics in a Schema
+
+Use schema-level metric discovery to find metrics across the current 
definitions of Semantic
+Models in one schema. You can list identifiers or retrieve complete metric 
definitions without
+first listing and loading each model. These examples use the `total_revenue` 
metric in
+`mart.sales_model` created above, before importing any other models.
+
+#### List Metric Identifiers
+
+<Tabs groupId='language' queryString>
+<TabItem value="shell" label="REST">
+
+```shell
+curl -X GET -H "Accept: application/vnd.gravitino.v1+json" \
+  
'http://localhost:8090/api/metalakes/example/catalogs/sales/schemas/mart/semantic-model-metrics'
+```
+
+The default is `details=false`; only `true` (case-insensitive) enables 
complete metric definitions.
+If `sales_model` is the only model with metrics in this schema, the default 
response is:
+
+```json
+{
+  "code": 0,
+  "identifiers": [
+    {
+      "namespace": ["example", "sales", "mart", "sales_model"],
+      "name": "total_revenue"
+    }
+  ]
+}
+```
+
+</TabItem>
+<TabItem value="java" label="Java">
+
+```java
+NameIdentifier[] metricIdentifiers = models.listMetrics(Namespace.of("mart"));
+```
+
+</TabItem>
+<TabItem value="python" label="Python">
+
+```python
+metric_identifiers = models.list_metrics(Namespace.of("mart"))
+```
+
+</TabItem>
+</Tabs>
+
+Metric names are unique within a model. Two models can both define 
`total_revenue`; use the
+namespace together with the metric name to distinguish them.
+
+| Interface | Namespace in each result | Metric name |
+|-----------|--------------------------|-------------|
+| REST | `["example", "sales", "mart", "sales_model"]` | `total_revenue` |
+| Java / Python, using the loaded `sales` catalog | `["mart", "sales_model"]` 
| `total_revenue` |
+
+The SDK methods accept a schema namespace, such as `Namespace.of("mart")`. Do 
not include the
+metalake, catalog, or model in that argument.
+
+#### Retrieve Metric Definitions
+
+<Tabs groupId='language' queryString>
+<TabItem value="shell" label="REST">
+
+```shell
+curl -X GET -H "Accept: application/vnd.gravitino.v1+json" \
+  
'http://localhost:8090/api/metalakes/example/catalogs/sales/schemas/mart/semantic-model-metrics?details=true'
+```
+
+For the same model, the response is:
+
+```json
+{
+  "code": 0,
+  "metrics": [
+    {
+      "namespace": ["example", "sales", "mart", "sales_model"],
+      "metric": {
+        "name": "total_revenue",
+        "expression": {
+          "dialects": [
+            {"dialect": "ANSI_SQL", "expression": "SUM(orders.order_amount)"}
+          ]
+        },
+        "datatype": "Decimal"
+      }
+    }
+  ]
+}
+```
+
+</TabItem>
+<TabItem value="java" label="Java">
+
+```java
+SemanticModelMetric[] metricInfos = 
models.listMetricInfos(Namespace.of("mart"));
+```
+
+</TabItem>
+<TabItem value="python" label="Python">
+
+```python
+metric_infos = models.list_metric_infos(Namespace.of("mart"))
+```
+
+</TabItem>
+</Tabs>
+
+Each SDK result exposes `namespace()` and `metric()`. The metric contains its 
name, expression,
+and any stored data type, description, AI context, or custom extensions. To 
construct its identifier,
+use `NameIdentifier.of(info.namespace(), info.metric().name())` in Java or
+`NameIdentifier.builder(info.namespace(), info.metric().name())` in Python.
+
+#### Ordering, Visibility, and Updates
+
+Both listing modes sort results by the containing model's identifier and then 
by case-sensitive
+metric name. Models without metrics contribute no entries. If there are no 
visible metrics, REST
+returns an empty `identifiers` or `metrics` array and the SDKs return an empty 
array or list.
+
+With authorization enabled, discovery requires access to the parent catalog 
and schema. It
+includes metrics only from models the caller can discover through 
`USE_SEMANTIC_MODEL`,
+`MODIFY_SEMANTIC_MODEL`, or ownership, as described in
+[Ownership and Privileges](#ownership-and-privileges). Discovery does not 
revalidate access to
+source tables or views and does not grant access to source data.
+
+Discovery reflects each model's current committed definition: renaming a model 
changes the
+namespace returned for its metrics, replacing its definition changes the 
discovered metrics,
+and dropping it removes its metrics from discovery. Manage metric definitions 
through their
+containing Semantic Models; discovery does not provide a separate metric 
lifecycle or execute
+metric expressions.
+
+An empty result is a successful discovery response. Missing schemas, denied 
parent access, and

Review Comment:
   nit: It may help SDK users to name the concrete errors here, e.g. 
`NoSuchSchemaException` (404) for a missing schema, `ForbiddenException` (403) 
for denied catalog/schema access, and `UnsupportedOperationException` (501) for 
non-relational catalogs.



##########
docs/manage-semantic-model-metadata-using-gravitino.md:
##########
@@ -326,6 +327,144 @@ loaded = models.load_semantic_model(ident)
 </TabItem>
 </Tabs>
 
+### Discover Metrics in a Schema
+
+Use schema-level metric discovery to find metrics across the current 
definitions of Semantic
+Models in one schema. You can list identifiers or retrieve complete metric 
definitions without
+first listing and loading each model. These examples use the `total_revenue` 
metric in
+`mart.sales_model` created above, before importing any other models.
+
+#### List Metric Identifiers
+
+<Tabs groupId='language' queryString>
+<TabItem value="shell" label="REST">
+
+```shell
+curl -X GET -H "Accept: application/vnd.gravitino.v1+json" \
+  
'http://localhost:8090/api/metalakes/example/catalogs/sales/schemas/mart/semantic-model-metrics'
+```
+
+The default is `details=false`; only `true` (case-insensitive) enables 
complete metric definitions.
+If `sales_model` is the only model with metrics in this schema, the default 
response is:
+
+```json
+{
+  "code": 0,
+  "identifiers": [
+    {
+      "namespace": ["example", "sales", "mart", "sales_model"],
+      "name": "total_revenue"
+    }
+  ]
+}
+```
+
+</TabItem>
+<TabItem value="java" label="Java">
+
+```java
+NameIdentifier[] metricIdentifiers = models.listMetrics(Namespace.of("mart"));
+```
+
+</TabItem>
+<TabItem value="python" label="Python">
+
+```python
+metric_identifiers = models.list_metrics(Namespace.of("mart"))
+```
+
+</TabItem>
+</Tabs>
+
+Metric names are unique within a model. Two models can both define 
`total_revenue`; use the
+namespace together with the metric name to distinguish them.
+
+| Interface | Namespace in each result | Metric name |
+|-----------|--------------------------|-------------|
+| REST | `["example", "sales", "mart", "sales_model"]` | `total_revenue` |
+| Java / Python, using the loaded `sales` catalog | `["mart", "sales_model"]` 
| `total_revenue` |
+
+The SDK methods accept a schema namespace, such as `Namespace.of("mart")`. Do 
not include the
+metalake, catalog, or model in that argument.
+
+#### Retrieve Metric Definitions
+
+<Tabs groupId='language' queryString>
+<TabItem value="shell" label="REST">
+
+```shell
+curl -X GET -H "Accept: application/vnd.gravitino.v1+json" \
+  
'http://localhost:8090/api/metalakes/example/catalogs/sales/schemas/mart/semantic-model-metrics?details=true'
+```
+
+For the same model, the response is:
+
+```json
+{
+  "code": 0,
+  "metrics": [
+    {
+      "namespace": ["example", "sales", "mart", "sales_model"],
+      "metric": {
+        "name": "total_revenue",
+        "expression": {
+          "dialects": [
+            {"dialect": "ANSI_SQL", "expression": "SUM(orders.order_amount)"}
+          ]
+        },
+        "datatype": "Decimal"
+      }
+    }
+  ]
+}
+```
+
+</TabItem>
+<TabItem value="java" label="Java">
+
+```java
+SemanticModelMetric[] metricInfos = 
models.listMetricInfos(Namespace.of("mart"));
+```
+
+</TabItem>
+<TabItem value="python" label="Python">
+
+```python
+metric_infos = models.list_metric_infos(Namespace.of("mart"))
+```
+
+</TabItem>
+</Tabs>
+
+Each SDK result exposes `namespace()` and `metric()`. The metric contains its 
name, expression,
+and any stored data type, description, AI context, or custom extensions. To 
construct its identifier,
+use `NameIdentifier.of(info.namespace(), info.metric().name())` in Java or
+`NameIdentifier.builder(info.namespace(), info.metric().name())` in Python.
+
+#### Ordering, Visibility, and Updates
+
+Both listing modes sort results by the containing model's identifier and then 
by case-sensitive

Review Comment:
   nit: Consider stating that discovery is not paginated: both modes return all 
visible metrics in the schema in a single response, so `details=true` can be 
large for schemas with many models.



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