Skip to content

Commit ff13cdd

Browse files
committed
incorporate review comments
- Accept inference table name from CLI - Merge monitoring related resources into a single file - Parametrize the metric and validation threshold
1 parent 0495122 commit ff13cdd

6 files changed

Lines changed: 66 additions & 34 deletions

File tree

databricks_template_schema.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,19 @@
301301
}
302302
]
303303
}
304+
},
305+
"input_inference_table_name": {
306+
"order": 19,
307+
"type": "string",
308+
"description": "\nName of inference table to attach monitoring to.\nThis table must already exist and service principals must have access.",
309+
"default": "predictions",
310+
"skip_prompt_if": {
311+
"properties": {
312+
"input_setup_cicd_and_project": {
313+
"const": "CICD_Only"
314+
}
315+
}
316+
}
304317
}
305318
},
306319
"success_message" : "\n*** Your MLOps Stack has been created in the '{{.input_root_dir}}{{if not (eq .input_setup_cicd_and_project `CICD_Only`) }}/{{.input_project_name}}{{end}}' directory! ***\n\nPlease refer to the README.md for further instructions on getting started."

template/{{.input_root_dir}}/{{template `project_name_alphanumeric_underscore` .}}/monitoring/metric_violation_check_query.py.tmpl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import pathlib
44
sys.path.append(str(pathlib.Path(__file__).parent.parent.parent.resolve()))
55

66
"""The SQL query is divided into three main parts. The first part selects the top 5
7-
values of the metric to be monitored, `root_mean_squared_error`,
7+
values of the metric to be monitored,
88
ordered by the time window.
99
```sql
1010
( SELECT
11-
root_mean_squared_error
11+
{metric_to_monitor}
1212
FROM
13-
{}_profile_metrics
13+
{table_name_under_monitor}_profile_metrics
1414
where
1515
column_name = ":table"
1616
and slice_key IS NULL
@@ -32,7 +32,7 @@ The second part of the query selects the metric values that exceed
3232
the defined threshold:
3333
```sql
3434
WHERE
35-
root_mean_squared_error > 100
35+
{metric_to_monitor} > {metric_violation_threshold}
3636
```
3737
The final part of the query sets the `query_result` to 1 if the threshold violation
3838
occurred more than twice within the checking interval, and 0 otherwise:
@@ -53,9 +53,9 @@ sql_query = """SELECT
5353
FROM
5454
(
5555
SELECT
56-
root_mean_squared_error
56+
{metric_to_monitor}
5757
FROM
58-
{}_profile_metrics
58+
{table_name_under_monitor}_profile_metrics
5959
where
6060
column_name = ":table"
6161
and slice_key IS NULL
@@ -67,4 +67,4 @@ FROM
6767
5
6868
)
6969
WHERE
70-
root_mean_squared_error > 100"""
70+
{metric_to_monitor} > {metric_violation_threshold}"""

template/{{.input_root_dir}}/{{template `project_name_alphanumeric_underscore` .}}/monitoring/notebooks/MonitoredMetricViolationCheck.py.tmpl

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,18 @@
1212
#
1313
# Name of the table that is currently being monitored
1414
dbutils.widgets.text(
15-
"table_name_under_monitor", " ${bundle.target}.{{ .input_project_name }}.predictions", label="Full (three-Level) table name"
15+
"table_name_under_monitor", " ${bundle.target}.{{ .input_project_name }}.{{ .input_inference_table_name }}", label="Full (three-Level) table name"
1616
)
17+
# Metric to be used for threshold violation check
18+
dbutils.widgets.text(
19+
"metric_to_monitor", "root_mean_squared_error", label="Metric to be monitored for threshold violation"
20+
)
21+
22+
# Threshold value to be checked
23+
dbutils.widgets.text(
24+
"metric_violation_threshold", "100", label="Threshold value for metric violation"
25+
)
26+
1727
# COMMAND ----------
1828

1929
import os
@@ -28,7 +38,14 @@ sys.path.append("../..")
2838
from metric_violation_check_query import sql_query
2939

3040
table_name_under_monitor = dbutils.widgets.get("table_name_under_monitor")
31-
is_metric_violated = bool(spark.sql(sql_query.format(table_name_under_monitor)).toPandas()["query_result"][0])
41+
metric_to_monitor = dbutils.widgets.get("metric_to_monitor")
42+
metric_violation_threshold = dbutils.widgets.get("metric_violation_threshold")
43+
44+
formatted_sql_query = sql_query.format(
45+
table_name_under_monitor=table_name_under_monitor,
46+
metric_to_monitor=metric_to_monitor,
47+
metric_violation_threshold=metric_violation_threshold)
48+
is_metric_violated = bool(spark.sql(formatted_sql_query).toPandas()["query_result"][0])
3249

3350
dbutils.jobs.taskValues.set("is_metric_violated", is_metric_violated)
3451

template/{{.input_root_dir}}/{{template `project_name_alphanumeric_underscore` .}}/resources/README.md.tmpl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,17 +151,16 @@ violation threshold defined given the ground truth labels.
151151
Its central purpose is to track production model performances, feature distributions and comparing different versions.
152152

153153
Monitoring contains four components:
154-
* [monitoring-resource.yml](./monitoring-resource.yml) contains the resource config and input parameters for monitoring.
155154
* [metric_violation_check_query.py](../monitoring/metric_violation_check_query.py) defines a query that check for violation of monitored metric.
156155
* [notebooks/MonitoredMetricViolationCheck](../monitoring/notebooks/MonitoredMetricViolationCheck.py) acts as an entry pointexecuting the violation check query against the monitored inference table.
157156
It emits a boolean value based on the query result.
158-
* [monitoring-workflow-resource.yml](./monitoring-workflow-resource.yml) orchestrates model retraining based on monitoring. It first runs the [notebooks/MonitoredMetricViolationCheck](../monitoring/notebooks/MonitoredMetricViolationCheck.py)
157+
* [monitoring-workflow-resource.yml](./monitoring-workflow-resource.yml) contains the resource config, input parameters for monitoring and orchestrates model retraining based on monitoring. It first runs the [notebooks/MonitoredMetricViolationCheck](../monitoring/notebooks/MonitoredMetricViolationCheck.py)
159158
entry point then decides whether to execute the model retraining workflow.
160159

161160
To set up and enable monitoring:
162161
* Update [metric_violation_check_query.py](../monitoring/metric_violation_check_query.py) to capture the specific metrics of interest,
163162
* Generate inference table, join it with ground truth labels,and update the table name in [monitoring-resource.yml](./monitoring-resource.yml).
164-
* Resolve the `TODOs` in [monitoring-resource.yml](./monitoring-resource.yml)
163+
* Resolve the `TODOs` in [monitoring-workflow-resource.yml](./monitoring-workflow-resource.yml)
165164

166165
Retraining Constraints:
167166
The retraining job has constraints for optimal functioning:

template/{{.input_root_dir}}/{{template `project_name_alphanumeric_underscore` .}}/resources/monitoring-resource.yml.tmpl

Lines changed: 0 additions & 20 deletions
This file was deleted.

template/{{.input_root_dir}}/{{template `project_name_alphanumeric_underscore` .}}/resources/monitoring-workflow-resource.yml.tmpl

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
1-
# Note: Lakehouse monitring only works for unity catalog enabled workspaces. Remove this workflow if your application
1+
# Define lakehouse monitor
2+
# Note: Lakehouse monitring only works for Unity catalog enabled workspaces. Remove this resource if your application
23
# is running on Non-UC workspaces
4+
5+
resources:
6+
lakehouse_monitors:
7+
{{ .input_project_name }}_lakehouse_monitor:
8+
# TODO: Update the table name to the inference table that already exists
9+
full_name: ${bundle.target}.{{ .input_project_name }}.{{ .input_inference_table_name }}
10+
output_schema_name: ${bundle.target}.{{ .input_project_name }}
11+
# TODO: Update the below parameters as per your requirements
12+
inference_log:
13+
granularities: [1 day]
14+
model_id_col: model_id
15+
prediction_col: predictions
16+
label_col: labels
17+
problem_type: PROBLEM_TYPE_REGRESSION
18+
timestamp_col: timestamp
19+
schedule:
20+
quartz_cron_expression: 0 0 8 * * ? # Run Every day at 8am
21+
timezone_id: UTC
22+
323
new_cluster: &new_cluster
424
new_cluster:
525
num_workers: 3
@@ -24,7 +44,10 @@ resources:
2444
notebook_path: ../monitoring/notebooks/MonitoredMetricViolationCheck.py
2545
base_parameters:
2646
env: ${bundle.target}
27-
table_name_under_monitor: ${bundle.target}.{{ .input_project_name }}.predictions
47+
table_name_under_monitor: ${bundle.target}.{{ .input_project_name }}.{{ .input_inference_table_name }}
48+
# TODO: Update the metric to be monitored and violation threshold
49+
metric_to_monitor: root_mean_squared_error
50+
metric_violation_threshold: 100
2851
# git source information of current ML resource deployment. It will be persisted as part of the workflow run
2952
git_source_info: url:${bundle.git.origin_url}; branch:${bundle.git.branch}; commit:${bundle.git.commit}
3053

0 commit comments

Comments
 (0)