mlrun 1.7.0rc4__py3-none-any.whl → 1.7.0rc20__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +11 -1
- mlrun/__main__.py +25 -111
- mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
- mlrun/alerts/alert.py +144 -0
- mlrun/api/schemas/__init__.py +4 -3
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +38 -254
- mlrun/artifacts/dataset.py +9 -190
- mlrun/artifacts/manager.py +41 -47
- mlrun/artifacts/model.py +30 -158
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +68 -0
- mlrun/common/formatters/__init__.py +19 -0
- mlrun/{model_monitoring/stores/models/sqlite.py → common/formatters/artifact.py} +6 -8
- mlrun/common/formatters/base.py +78 -0
- mlrun/common/formatters/function.py +41 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/{runtimes → common/runtimes}/constants.py +32 -4
- mlrun/common/schemas/__init__.py +25 -4
- mlrun/common/schemas/alert.py +203 -0
- mlrun/common/schemas/api_gateway.py +148 -0
- mlrun/common/schemas/artifact.py +15 -5
- mlrun/common/schemas/auth.py +8 -2
- mlrun/common/schemas/client_spec.py +2 -0
- mlrun/common/schemas/frontend_spec.py +1 -0
- mlrun/common/schemas/function.py +4 -0
- mlrun/common/schemas/hub.py +7 -9
- mlrun/common/schemas/model_monitoring/__init__.py +19 -3
- mlrun/common/schemas/model_monitoring/constants.py +96 -26
- mlrun/common/schemas/model_monitoring/grafana.py +9 -5
- mlrun/common/schemas/model_monitoring/model_endpoints.py +86 -2
- mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
- mlrun/common/schemas/pipeline.py +0 -9
- mlrun/common/schemas/project.py +22 -21
- mlrun/common/types.py +7 -1
- mlrun/config.py +87 -19
- mlrun/data_types/data_types.py +4 -0
- mlrun/data_types/to_pandas.py +9 -9
- mlrun/datastore/__init__.py +5 -8
- mlrun/datastore/alibaba_oss.py +130 -0
- mlrun/datastore/azure_blob.py +4 -5
- mlrun/datastore/base.py +69 -30
- mlrun/datastore/datastore.py +10 -2
- mlrun/datastore/datastore_profile.py +90 -6
- mlrun/datastore/google_cloud_storage.py +1 -1
- mlrun/datastore/hdfs.py +5 -0
- mlrun/datastore/inmem.py +2 -2
- mlrun/datastore/redis.py +2 -2
- mlrun/datastore/s3.py +5 -0
- mlrun/datastore/snowflake_utils.py +43 -0
- mlrun/datastore/sources.py +172 -44
- mlrun/datastore/store_resources.py +7 -7
- mlrun/datastore/targets.py +285 -41
- mlrun/datastore/utils.py +68 -5
- mlrun/datastore/v3io.py +27 -50
- mlrun/db/auth_utils.py +152 -0
- mlrun/db/base.py +149 -14
- mlrun/db/factory.py +1 -1
- mlrun/db/httpdb.py +608 -178
- mlrun/db/nopdb.py +191 -7
- mlrun/errors.py +11 -0
- mlrun/execution.py +37 -20
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +21 -52
- mlrun/feature_store/feature_set.py +48 -23
- mlrun/feature_store/feature_vector.py +2 -1
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +9 -4
- mlrun/feature_store/retrieval/conversion.py +9 -9
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +9 -3
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +34 -24
- mlrun/feature_store/steps.py +30 -19
- mlrun/features.py +4 -13
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +2 -2
- mlrun/frameworks/lgbm/__init__.py +1 -1
- mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
- mlrun/frameworks/lgbm/model_handler.py +1 -1
- mlrun/frameworks/parallel_coordinates.py +2 -1
- mlrun/frameworks/pytorch/__init__.py +2 -2
- mlrun/frameworks/sklearn/__init__.py +1 -1
- mlrun/frameworks/tf_keras/__init__.py +5 -2
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/mlrun_interface.py +2 -2
- mlrun/frameworks/xgboost/__init__.py +1 -1
- mlrun/k8s_utils.py +10 -11
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +6 -5
- mlrun/launcher/client.py +8 -6
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +9 -3
- mlrun/launcher/remote.py +9 -3
- mlrun/lists.py +6 -2
- mlrun/model.py +58 -19
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +127 -301
- mlrun/model_monitoring/application.py +5 -296
- mlrun/model_monitoring/applications/__init__.py +11 -0
- mlrun/model_monitoring/applications/_application_steps.py +157 -0
- mlrun/model_monitoring/applications/base.py +282 -0
- mlrun/model_monitoring/applications/context.py +214 -0
- mlrun/model_monitoring/applications/evidently_base.py +211 -0
- mlrun/model_monitoring/applications/histogram_data_drift.py +224 -93
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +30 -36
- mlrun/model_monitoring/db/__init__.py +18 -0
- mlrun/model_monitoring/{stores → db/stores}/__init__.py +43 -36
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/{stores/model_endpoint_store.py → db/stores/base/store.py} +58 -32
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/{stores → db/stores/sqldb}/models/base.py +109 -5
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +88 -0
- mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +684 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/{stores/kv_model_endpoint_store.py → db/stores/v3io_kv/kv_store.py} +302 -155
- mlrun/model_monitoring/db/tsdb/__init__.py +100 -0
- mlrun/model_monitoring/db/tsdb/base.py +329 -0
- mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
- mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +240 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +45 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +397 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +630 -0
- mlrun/model_monitoring/evidently_application.py +6 -118
- mlrun/model_monitoring/features_drift_table.py +34 -22
- mlrun/model_monitoring/helpers.py +100 -7
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +93 -228
- mlrun/model_monitoring/tracking_policy.py +7 -1
- mlrun/model_monitoring/writer.py +152 -124
- mlrun/package/packagers_manager.py +1 -0
- mlrun/package/utils/_formatter.py +2 -2
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +21 -202
- mlrun/projects/operations.py +30 -16
- mlrun/projects/pipelines.py +92 -99
- mlrun/projects/project.py +757 -268
- mlrun/render.py +15 -14
- mlrun/run.py +160 -162
- mlrun/runtimes/__init__.py +55 -3
- mlrun/runtimes/base.py +33 -19
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +0 -28
- mlrun/runtimes/kubejob.py +28 -122
- mlrun/runtimes/local.py +5 -2
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/abstract.py +8 -8
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/runtimes/nuclio/__init__.py +1 -0
- mlrun/runtimes/nuclio/api_gateway.py +709 -0
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +523 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/nuclio/function.py +98 -58
- mlrun/runtimes/nuclio/serving.py +36 -42
- mlrun/runtimes/pod.py +196 -45
- mlrun/runtimes/remotesparkjob.py +1 -1
- mlrun/runtimes/sparkjob/spark3job.py +1 -1
- mlrun/runtimes/utils.py +6 -73
- mlrun/secrets.py +6 -2
- mlrun/serving/remote.py +2 -3
- mlrun/serving/routers.py +7 -4
- mlrun/serving/server.py +7 -8
- mlrun/serving/states.py +73 -43
- mlrun/serving/v2_serving.py +8 -7
- mlrun/track/tracker.py +2 -1
- mlrun/utils/async_http.py +25 -5
- mlrun/utils/helpers.py +141 -75
- mlrun/utils/http.py +1 -1
- mlrun/utils/logger.py +39 -7
- mlrun/utils/notifications/notification/__init__.py +14 -9
- mlrun/utils/notifications/notification/base.py +12 -0
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +3 -1
- mlrun/utils/notifications/notification/ipython.py +2 -0
- mlrun/utils/notifications/notification/slack.py +101 -21
- mlrun/utils/notifications/notification/webhook.py +11 -1
- mlrun/utils/notifications/notification_pusher.py +147 -16
- mlrun/utils/retryer.py +3 -2
- mlrun/utils/v3io_clients.py +0 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/METADATA +33 -18
- mlrun-1.7.0rc20.dist-info/RECORD +353 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/WHEEL +1 -1
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/batch.py +0 -974
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
- mlrun/platforms/other.py +0 -305
- mlrun-1.7.0rc4.dist-info/RECORD +0 -321
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Copyright 2023 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import dataclasses
|
|
16
|
+
import json
|
|
17
|
+
import re
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
|
|
20
|
+
import mlrun.common.helpers
|
|
21
|
+
import mlrun.common.model_monitoring.helpers
|
|
22
|
+
import mlrun.common.schemas.model_monitoring.constants as mm_constant
|
|
23
|
+
import mlrun.utils.v3io_clients
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class _ModelMonitoringApplicationDataRes(ABC):
|
|
27
|
+
name: str
|
|
28
|
+
|
|
29
|
+
def __post_init__(self):
|
|
30
|
+
pat = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*")
|
|
31
|
+
if not re.fullmatch(pat, self.name):
|
|
32
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
33
|
+
"Attribute name must be of the format [a-zA-Z_][a-zA-Z0-9_]*"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def to_dict(self):
|
|
38
|
+
raise NotImplementedError
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclasses.dataclass
|
|
42
|
+
class ModelMonitoringApplicationResult(_ModelMonitoringApplicationDataRes):
|
|
43
|
+
"""
|
|
44
|
+
Class representing the result of a custom model monitoring application.
|
|
45
|
+
|
|
46
|
+
:param name: (str) Name of the application result. This name must be
|
|
47
|
+
unique for each metric in a single application
|
|
48
|
+
(name must be of the format [a-zA-Z_][a-zA-Z0-9_]*).
|
|
49
|
+
:param value: (float) Value of the application result.
|
|
50
|
+
:param kind: (ResultKindApp) Kind of application result.
|
|
51
|
+
:param status: (ResultStatusApp) Status of the application result.
|
|
52
|
+
:param extra_data: (dict) Extra data associated with the application result.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
name: str
|
|
56
|
+
value: float
|
|
57
|
+
kind: mm_constant.ResultKindApp
|
|
58
|
+
status: mm_constant.ResultStatusApp
|
|
59
|
+
extra_data: dict = dataclasses.field(default_factory=dict)
|
|
60
|
+
|
|
61
|
+
def to_dict(self):
|
|
62
|
+
"""
|
|
63
|
+
Convert the object to a dictionary format suitable for writing.
|
|
64
|
+
|
|
65
|
+
:returns: (dict) Dictionary representation of the result.
|
|
66
|
+
"""
|
|
67
|
+
return {
|
|
68
|
+
mm_constant.ResultData.RESULT_NAME: self.name,
|
|
69
|
+
mm_constant.ResultData.RESULT_VALUE: self.value,
|
|
70
|
+
mm_constant.ResultData.RESULT_KIND: self.kind.value,
|
|
71
|
+
mm_constant.ResultData.RESULT_STATUS: self.status.value,
|
|
72
|
+
mm_constant.ResultData.RESULT_EXTRA_DATA: json.dumps(self.extra_data),
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclasses.dataclass
|
|
77
|
+
class ModelMonitoringApplicationMetric(_ModelMonitoringApplicationDataRes):
|
|
78
|
+
"""
|
|
79
|
+
Class representing a single metric of a custom model monitoring application.
|
|
80
|
+
|
|
81
|
+
:param name: (str) Name of the application metric. This name must be
|
|
82
|
+
unique for each metric in a single application
|
|
83
|
+
(name must be of the format [a-zA-Z_][a-zA-Z0-9_]*).
|
|
84
|
+
:param value: (float) Value of the application metric.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
name: str
|
|
88
|
+
value: float
|
|
89
|
+
|
|
90
|
+
def to_dict(self):
|
|
91
|
+
"""
|
|
92
|
+
Convert the object to a dictionary format suitable for writing.
|
|
93
|
+
|
|
94
|
+
:returns: (dict) Dictionary representation of the result.
|
|
95
|
+
"""
|
|
96
|
+
return {
|
|
97
|
+
mm_constant.MetricData.METRIC_NAME: self.name,
|
|
98
|
+
mm_constant.MetricData.METRIC_VALUE: self.value,
|
|
99
|
+
}
|
|
@@ -21,25 +21,24 @@ from collections.abc import Iterator
|
|
|
21
21
|
from typing import Any, NamedTuple, Optional, Union, cast
|
|
22
22
|
|
|
23
23
|
import nuclio
|
|
24
|
-
from v3io.dataplane.response import HttpResponseError
|
|
25
24
|
|
|
26
25
|
import mlrun
|
|
27
26
|
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
28
27
|
import mlrun.data_types.infer
|
|
29
28
|
import mlrun.feature_store as fstore
|
|
29
|
+
import mlrun.model_monitoring.db.stores
|
|
30
30
|
from mlrun.common.model_monitoring.helpers import FeatureStats, pad_features_hist
|
|
31
31
|
from mlrun.datastore import get_stream_pusher
|
|
32
32
|
from mlrun.datastore.targets import ParquetTarget
|
|
33
33
|
from mlrun.errors import err_to_str
|
|
34
|
-
from mlrun.model_monitoring.batch import calculate_inputs_statistics
|
|
35
34
|
from mlrun.model_monitoring.helpers import (
|
|
36
35
|
_BatchDict,
|
|
37
36
|
batch_dict2timedelta,
|
|
37
|
+
calculate_inputs_statistics,
|
|
38
38
|
get_monitoring_parquet_path,
|
|
39
39
|
get_stream_path,
|
|
40
40
|
)
|
|
41
|
-
from mlrun.utils import
|
|
42
|
-
from mlrun.utils.v3io_clients import get_v3io_client
|
|
41
|
+
from mlrun.utils import datetime_now, logger
|
|
43
42
|
|
|
44
43
|
|
|
45
44
|
class _Interval(NamedTuple):
|
|
@@ -48,8 +47,6 @@ class _Interval(NamedTuple):
|
|
|
48
47
|
|
|
49
48
|
|
|
50
49
|
class _BatchWindow:
|
|
51
|
-
V3IO_CONTAINER_FORMAT = "users/pipelines/{project}/monitoring-schedules/functions"
|
|
52
|
-
|
|
53
50
|
def __init__(
|
|
54
51
|
self,
|
|
55
52
|
project: str,
|
|
@@ -65,27 +62,22 @@ class _BatchWindow:
|
|
|
65
62
|
All the time values are in seconds.
|
|
66
63
|
The start and stop time are in seconds since the epoch.
|
|
67
64
|
"""
|
|
65
|
+
self.project = project
|
|
68
66
|
self._endpoint = endpoint
|
|
69
67
|
self._application = application
|
|
70
68
|
self._first_request = first_request
|
|
71
|
-
self._kv_storage = get_v3io_client(
|
|
72
|
-
endpoint=mlrun.mlconf.v3io_api,
|
|
73
|
-
# Avoid noisy warning logs before the KV table is created
|
|
74
|
-
logger=create_logger(name="v3io_client", level="error"),
|
|
75
|
-
).kv
|
|
76
|
-
self._v3io_container = self.V3IO_CONTAINER_FORMAT.format(project=project)
|
|
77
69
|
self._stop = last_updated
|
|
78
70
|
self._step = timedelta_seconds
|
|
71
|
+
self._db = mlrun.model_monitoring.get_store_object(project=self.project)
|
|
79
72
|
self._start = self._get_last_analyzed()
|
|
80
73
|
|
|
81
74
|
def _get_last_analyzed(self) -> Optional[int]:
|
|
82
75
|
try:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
key=self._application,
|
|
76
|
+
last_analyzed = self._db.get_last_analyzed(
|
|
77
|
+
endpoint_id=self._endpoint,
|
|
78
|
+
application_name=self._application,
|
|
87
79
|
)
|
|
88
|
-
except
|
|
80
|
+
except mlrun.errors.MLRunNotFoundError:
|
|
89
81
|
logger.info(
|
|
90
82
|
"No last analyzed time was found for this endpoint and "
|
|
91
83
|
"application, as this is probably the first time this "
|
|
@@ -96,7 +88,7 @@ class _BatchWindow:
|
|
|
96
88
|
first_request=self._first_request,
|
|
97
89
|
last_updated=self._stop,
|
|
98
90
|
)
|
|
99
|
-
|
|
91
|
+
|
|
100
92
|
if self._first_request and self._stop:
|
|
101
93
|
# TODO : Change the timedelta according to the policy.
|
|
102
94
|
first_period_in_seconds = max(
|
|
@@ -108,7 +100,6 @@ class _BatchWindow:
|
|
|
108
100
|
)
|
|
109
101
|
return self._first_request
|
|
110
102
|
|
|
111
|
-
last_analyzed = data.output.item[mm_constants.SchedulingKeys.LAST_ANALYZED]
|
|
112
103
|
logger.info(
|
|
113
104
|
"Got the last analyzed time for this endpoint and application",
|
|
114
105
|
endpoint=self._endpoint,
|
|
@@ -124,11 +115,11 @@ class _BatchWindow:
|
|
|
124
115
|
application=self._application,
|
|
125
116
|
last_analyzed=last_analyzed,
|
|
126
117
|
)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
|
|
119
|
+
self._db.update_last_analyzed(
|
|
120
|
+
endpoint_id=self._endpoint,
|
|
121
|
+
application_name=self._application,
|
|
122
|
+
last_analyzed=last_analyzed,
|
|
132
123
|
)
|
|
133
124
|
|
|
134
125
|
def get_intervals(
|
|
@@ -301,7 +292,7 @@ class MonitoringApplicationController:
|
|
|
301
292
|
f"Initializing {self.__class__.__name__}", project=project
|
|
302
293
|
)
|
|
303
294
|
|
|
304
|
-
self.db = mlrun.model_monitoring.
|
|
295
|
+
self.db = mlrun.model_monitoring.get_store_object(project=project)
|
|
305
296
|
|
|
306
297
|
self._batch_window_generator = _BatchWindowGenerator(
|
|
307
298
|
batch_dict=json.loads(
|
|
@@ -359,7 +350,12 @@ class MonitoringApplicationController:
|
|
|
359
350
|
{
|
|
360
351
|
app.metadata.name
|
|
361
352
|
for app in monitoring_functions
|
|
362
|
-
if
|
|
353
|
+
if (
|
|
354
|
+
app.status.state == "ready"
|
|
355
|
+
# workaround for the default app, as its `status.state` is `None`
|
|
356
|
+
or app.metadata.name
|
|
357
|
+
== mm_constants.HistogramDataDriftApplicationConstants.NAME
|
|
358
|
+
)
|
|
363
359
|
}
|
|
364
360
|
)
|
|
365
361
|
if not applications_names:
|
|
@@ -367,6 +363,10 @@ class MonitoringApplicationController:
|
|
|
367
363
|
"No monitoring functions found", project=self.project
|
|
368
364
|
)
|
|
369
365
|
return
|
|
366
|
+
self.context.logger.info(
|
|
367
|
+
"Starting to iterate over the applications",
|
|
368
|
+
applications=applications_names,
|
|
369
|
+
)
|
|
370
370
|
|
|
371
371
|
except Exception as e:
|
|
372
372
|
self.context.logger.error(
|
|
@@ -445,13 +445,6 @@ class MonitoringApplicationController:
|
|
|
445
445
|
m_fs = fstore.get_feature_set(
|
|
446
446
|
endpoint[mm_constants.EventFieldType.FEATURE_SET_URI]
|
|
447
447
|
)
|
|
448
|
-
labels = endpoint[mm_constants.EventFieldType.LABEL_NAMES]
|
|
449
|
-
if labels:
|
|
450
|
-
if isinstance(labels, str):
|
|
451
|
-
labels = json.loads(labels)
|
|
452
|
-
for label in labels:
|
|
453
|
-
if label not in list(m_fs.spec.features.keys()):
|
|
454
|
-
m_fs.add_feature(fstore.Feature(name=label, value_type="float"))
|
|
455
448
|
|
|
456
449
|
for application in applications_names:
|
|
457
450
|
batch_window = batch_window_generator.get_batch_window(
|
|
@@ -464,6 +457,7 @@ class MonitoringApplicationController:
|
|
|
464
457
|
)
|
|
465
458
|
|
|
466
459
|
for start_infer_time, end_infer_time in batch_window.get_intervals():
|
|
460
|
+
# start - TODO : delete in 1.9.0 (V1 app deprecation)
|
|
467
461
|
try:
|
|
468
462
|
# Get application sample data
|
|
469
463
|
offline_response = cls._get_sample_df(
|
|
@@ -509,10 +503,9 @@ class MonitoringApplicationController:
|
|
|
509
503
|
|
|
510
504
|
# Get the current stats:
|
|
511
505
|
current_stats = calculate_inputs_statistics(
|
|
512
|
-
sample_set_statistics=feature_stats,
|
|
513
|
-
inputs=df,
|
|
506
|
+
sample_set_statistics=feature_stats, inputs=df
|
|
514
507
|
)
|
|
515
|
-
|
|
508
|
+
# end - TODO : delete in 1.9.0 (V1 app deprecation)
|
|
516
509
|
cls._push_to_applications(
|
|
517
510
|
current_stats=current_stats,
|
|
518
511
|
feature_stats=feature_stats,
|
|
@@ -621,6 +614,7 @@ class MonitoringApplicationController:
|
|
|
621
614
|
project=project,
|
|
622
615
|
function_name=mm_constants.MonitoringFunctionNames.WRITER,
|
|
623
616
|
),
|
|
617
|
+
mm_constants.ApplicationEvent.MLRUN_CONTEXT: {}, # TODO : for future use by ad-hoc batch infer
|
|
624
618
|
}
|
|
625
619
|
for app_name in applications_names:
|
|
626
620
|
data.update({mm_constants.ApplicationEvent.APPLICATION_NAME: app_name})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Copyright 2024 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from .stores import ObjectStoreFactory, get_store_object
|
|
16
|
+
from .stores.base import StoreBase
|
|
17
|
+
from .tsdb import get_tsdb_connector
|
|
18
|
+
from .tsdb.base import TSDBConnector
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2024 Iguazio
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -12,64 +12,56 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
# flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
|
|
16
|
-
|
|
17
15
|
import enum
|
|
18
16
|
import typing
|
|
17
|
+
import warnings
|
|
19
18
|
|
|
20
19
|
import mlrun.common.schemas.secret
|
|
21
20
|
import mlrun.errors
|
|
22
21
|
|
|
23
|
-
from .
|
|
22
|
+
from .base import StoreBase
|
|
24
23
|
|
|
25
24
|
|
|
26
|
-
class
|
|
27
|
-
"""Enum class to handle the different store type values for saving
|
|
25
|
+
class ObjectStoreFactory(enum.Enum):
|
|
26
|
+
"""Enum class to handle the different store type values for saving model monitoring records."""
|
|
28
27
|
|
|
29
28
|
v3io_nosql = "v3io-nosql"
|
|
30
29
|
SQL = "sql"
|
|
31
30
|
|
|
32
|
-
def
|
|
31
|
+
def to_object_store(
|
|
33
32
|
self,
|
|
34
33
|
project: str,
|
|
35
34
|
access_key: str = None,
|
|
36
|
-
endpoint_store_connection: str = None,
|
|
37
35
|
secret_provider: typing.Callable = None,
|
|
38
|
-
) ->
|
|
36
|
+
) -> StoreBase:
|
|
39
37
|
"""
|
|
40
|
-
Return a
|
|
41
|
-
|
|
42
|
-
:param project:
|
|
43
|
-
:param access_key:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
:param endpoint_store_connection: A valid connection string for model endpoint target. Contains several
|
|
47
|
-
key-value pairs that required for the database connection.
|
|
48
|
-
e.g. A root user with password 1234, tries to connect a schema called
|
|
49
|
-
mlrun within a local MySQL DB instance:
|
|
50
|
-
'mysql+pymysql://root:1234@localhost:3306/mlrun'.
|
|
38
|
+
Return a StoreBase object based on the provided enum value.
|
|
39
|
+
|
|
40
|
+
:param project: The name of the project.
|
|
41
|
+
:param access_key: Access key with permission to the DB table. Note that if access key is None
|
|
42
|
+
and the endpoint target is from type KV then the access key will be
|
|
43
|
+
retrieved from the environment variable.
|
|
51
44
|
:param secret_provider: An optional secret provider to get the connection string secret.
|
|
52
45
|
|
|
53
|
-
:return: `
|
|
46
|
+
:return: `StoreBase` object.
|
|
54
47
|
|
|
55
48
|
"""
|
|
56
49
|
|
|
57
|
-
if self
|
|
58
|
-
from .
|
|
50
|
+
if self == self.v3io_nosql:
|
|
51
|
+
from mlrun.model_monitoring.db.stores.v3io_kv.kv_store import KVStoreBase
|
|
59
52
|
|
|
60
53
|
# Get V3IO access key from env
|
|
61
54
|
access_key = access_key or mlrun.mlconf.get_v3io_access_key()
|
|
62
55
|
|
|
63
|
-
return
|
|
56
|
+
return KVStoreBase(project=project, access_key=access_key)
|
|
64
57
|
|
|
65
58
|
# Assuming SQL store target if store type is not KV.
|
|
66
59
|
# Update these lines once there are more than two store target types.
|
|
67
60
|
|
|
68
|
-
from .
|
|
61
|
+
from mlrun.model_monitoring.db.stores.sqldb.sql_store import SQLStoreBase
|
|
69
62
|
|
|
70
|
-
return
|
|
63
|
+
return SQLStoreBase(
|
|
71
64
|
project=project,
|
|
72
|
-
sql_connection_string=endpoint_store_connection,
|
|
73
65
|
secret_provider=secret_provider,
|
|
74
66
|
)
|
|
75
67
|
|
|
@@ -88,7 +80,24 @@ def get_model_endpoint_store(
|
|
|
88
80
|
project: str,
|
|
89
81
|
access_key: str = None,
|
|
90
82
|
secret_provider: typing.Callable = None,
|
|
91
|
-
) ->
|
|
83
|
+
) -> StoreBase:
|
|
84
|
+
# Leaving here for backwards compatibility
|
|
85
|
+
warnings.warn(
|
|
86
|
+
"The 'get_model_endpoint_store' function is deprecated and will be removed in 1.9.0. "
|
|
87
|
+
"Please use `get_store_object` instead.",
|
|
88
|
+
# TODO: remove in 1.9.0
|
|
89
|
+
FutureWarning,
|
|
90
|
+
)
|
|
91
|
+
return get_store_object(
|
|
92
|
+
project=project, access_key=access_key, secret_provider=secret_provider
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_store_object(
|
|
97
|
+
project: str,
|
|
98
|
+
access_key: str = None,
|
|
99
|
+
secret_provider: typing.Callable = None,
|
|
100
|
+
) -> StoreBase:
|
|
92
101
|
"""
|
|
93
102
|
Getting the DB target type based on mlrun.config.model_endpoint_monitoring.store_type.
|
|
94
103
|
|
|
@@ -96,16 +105,14 @@ def get_model_endpoint_store(
|
|
|
96
105
|
:param access_key: Access key with permission to the DB table.
|
|
97
106
|
:param secret_provider: An optional secret provider to get the connection string secret.
|
|
98
107
|
|
|
99
|
-
:return: `
|
|
100
|
-
model
|
|
108
|
+
:return: `StoreBase` object. Using this object, the user can apply different operations on the
|
|
109
|
+
model monitoring record such as write, update, get and delete a model endpoint.
|
|
101
110
|
"""
|
|
102
111
|
|
|
103
|
-
# Get store type value from
|
|
104
|
-
|
|
105
|
-
mlrun.mlconf.model_endpoint_monitoring.store_type
|
|
106
|
-
)
|
|
112
|
+
# Get store type value from ObjectStoreFactory enum class
|
|
113
|
+
store_type = ObjectStoreFactory(mlrun.mlconf.model_endpoint_monitoring.store_type)
|
|
107
114
|
|
|
108
|
-
# Convert into
|
|
109
|
-
return
|
|
115
|
+
# Convert into store target object
|
|
116
|
+
return store_type.to_object_store(
|
|
110
117
|
project=project, access_key=access_key, secret_provider=secret_provider
|
|
111
118
|
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2024 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from .store import StoreBase
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2024 Iguazio
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -11,22 +11,23 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
#
|
|
15
14
|
|
|
16
15
|
import typing
|
|
17
16
|
from abc import ABC, abstractmethod
|
|
18
17
|
|
|
18
|
+
import mlrun.common.schemas.model_monitoring as mm_schemas
|
|
19
|
+
|
|
19
20
|
|
|
20
|
-
class
|
|
21
|
+
class StoreBase(ABC):
|
|
21
22
|
"""
|
|
22
|
-
An abstract class to handle the
|
|
23
|
+
An abstract class to handle the store object in the DB target.
|
|
23
24
|
"""
|
|
24
25
|
|
|
25
26
|
def __init__(self, project: str):
|
|
26
27
|
"""
|
|
27
|
-
Initialize a new
|
|
28
|
+
Initialize a new store target.
|
|
28
29
|
|
|
29
|
-
:param project:
|
|
30
|
+
:param project: The name of the project.
|
|
30
31
|
"""
|
|
31
32
|
self.project = project
|
|
32
33
|
|
|
@@ -63,12 +64,10 @@ class ModelEndpointStore(ABC):
|
|
|
63
64
|
pass
|
|
64
65
|
|
|
65
66
|
@abstractmethod
|
|
66
|
-
def delete_model_endpoints_resources(self
|
|
67
|
+
def delete_model_endpoints_resources(self):
|
|
67
68
|
"""
|
|
68
69
|
Delete all model endpoints resources.
|
|
69
70
|
|
|
70
|
-
:param endpoints: A list of model endpoints flattened dictionaries.
|
|
71
|
-
|
|
72
71
|
"""
|
|
73
72
|
pass
|
|
74
73
|
|
|
@@ -113,33 +112,60 @@ class ModelEndpointStore(ABC):
|
|
|
113
112
|
pass
|
|
114
113
|
|
|
115
114
|
@abstractmethod
|
|
116
|
-
def
|
|
115
|
+
def write_application_event(
|
|
117
116
|
self,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
end: str = "now",
|
|
122
|
-
access_key: str = None,
|
|
123
|
-
) -> dict[str, list[tuple[str, float]]]:
|
|
117
|
+
event: dict[str, typing.Any],
|
|
118
|
+
kind: mm_schemas.WriterEventKind = mm_schemas.WriterEventKind.RESULT,
|
|
119
|
+
) -> None:
|
|
124
120
|
"""
|
|
125
|
-
|
|
126
|
-
|
|
121
|
+
Write a new event in the target table.
|
|
122
|
+
|
|
123
|
+
:param event: An event dictionary that represents the application result, should be corresponded to the
|
|
124
|
+
schema defined in the :py:class:`~mlrun.common.schemas.model_monitoring.constants.WriterEvent`
|
|
125
|
+
object.
|
|
126
|
+
:param kind: The type of the event, can be either "result" or "metric".
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
@abstractmethod
|
|
130
|
+
def get_last_analyzed(self, endpoint_id: str, application_name: str) -> int:
|
|
131
|
+
"""
|
|
132
|
+
Get the last analyzed time for the provided model endpoint and application.
|
|
127
133
|
|
|
128
134
|
:param endpoint_id: The unique id of the model endpoint.
|
|
129
|
-
:param
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
:
|
|
142
|
-
|
|
135
|
+
:param application_name: Registered application name.
|
|
136
|
+
|
|
137
|
+
:return: Timestamp as a Unix time.
|
|
138
|
+
:raise: MLRunNotFoundError if last analyzed value is not found.
|
|
139
|
+
"""
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
@abstractmethod
|
|
143
|
+
def update_last_analyzed(
|
|
144
|
+
self,
|
|
145
|
+
endpoint_id: str,
|
|
146
|
+
application_name: str,
|
|
147
|
+
last_analyzed: int,
|
|
148
|
+
):
|
|
143
149
|
"""
|
|
150
|
+
Update the last analyzed time for the provided model endpoint and application.
|
|
144
151
|
|
|
152
|
+
:param endpoint_id: The unique id of the model endpoint.
|
|
153
|
+
:param application_name: Registered application name.
|
|
154
|
+
:param last_analyzed: Timestamp as a Unix time that represents the last analyzed time of a certain
|
|
155
|
+
application and model endpoint.
|
|
156
|
+
|
|
157
|
+
"""
|
|
145
158
|
pass
|
|
159
|
+
|
|
160
|
+
@abstractmethod
|
|
161
|
+
def get_model_endpoint_metrics(
|
|
162
|
+
self, endpoint_id: str, type: mm_schemas.ModelEndpointMonitoringMetricType
|
|
163
|
+
) -> list[mm_schemas.ModelEndpointMonitoringMetric]:
|
|
164
|
+
"""
|
|
165
|
+
Get the model monitoring results and metrics of the requested model endpoint.
|
|
166
|
+
|
|
167
|
+
:param: endpoint_id: The model endpoint identifier.
|
|
168
|
+
:param: type: The type of the requested metrics ("result" or "metric").
|
|
169
|
+
|
|
170
|
+
:return: A list of the available metrics.
|
|
171
|
+
"""
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2024 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Copyright 2023 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from functools import partial
|
|
16
|
+
from typing import Optional, TypeVar, Union
|
|
17
|
+
|
|
18
|
+
from .mysql import ApplicationMetricsTable as MySQLApplicationMetricsTable
|
|
19
|
+
from .mysql import ApplicationResultTable as MySQLApplicationResultTable
|
|
20
|
+
from .mysql import ModelEndpointsTable as MySQLModelEndpointsTable
|
|
21
|
+
from .mysql import MonitoringSchedulesTable as MySQLMonitoringSchedulesTable
|
|
22
|
+
from .sqlite import ApplicationMetricsTable as SQLiteApplicationMetricsTable
|
|
23
|
+
from .sqlite import ApplicationResultTable as SQLiteApplicationResultTable
|
|
24
|
+
from .sqlite import ModelEndpointsTable as SQLiteModelEndpointsTable
|
|
25
|
+
from .sqlite import MonitoringSchedulesTable as SQLiteMonitoringSchedulesTable
|
|
26
|
+
|
|
27
|
+
MySQLTableType = TypeVar("MySQLTableType")
|
|
28
|
+
SQLiteTableType = TypeVar("SQLiteTableType")
|
|
29
|
+
|
|
30
|
+
_MYSQL_SCHEME = "mysql:"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _get_sql_table(
|
|
34
|
+
*,
|
|
35
|
+
mysql_table: MySQLTableType,
|
|
36
|
+
sqlite_table: SQLiteTableType,
|
|
37
|
+
connection_string: Optional[str] = None,
|
|
38
|
+
) -> Union[MySQLTableType, SQLiteTableType]:
|
|
39
|
+
"""
|
|
40
|
+
Return a SQLAlchemy table for MySQL or SQLite according to the connection string.
|
|
41
|
+
Note: this function should not be directly used in other modules.
|
|
42
|
+
"""
|
|
43
|
+
if connection_string and _MYSQL_SCHEME in connection_string:
|
|
44
|
+
return mysql_table
|
|
45
|
+
return sqlite_table
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
_get_model_endpoints_table = partial(
|
|
49
|
+
_get_sql_table,
|
|
50
|
+
mysql_table=MySQLModelEndpointsTable,
|
|
51
|
+
sqlite_table=SQLiteModelEndpointsTable,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
_get_application_result_table = partial(
|
|
56
|
+
_get_sql_table,
|
|
57
|
+
mysql_table=MySQLApplicationResultTable,
|
|
58
|
+
sqlite_table=SQLiteApplicationResultTable,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
_get_application_metrics_table = partial(
|
|
62
|
+
_get_sql_table,
|
|
63
|
+
mysql_table=MySQLApplicationMetricsTable,
|
|
64
|
+
sqlite_table=SQLiteApplicationMetricsTable,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
_get_monitoring_schedules_table = partial(
|
|
68
|
+
_get_sql_table,
|
|
69
|
+
mysql_table=MySQLMonitoringSchedulesTable,
|
|
70
|
+
sqlite_table=SQLiteMonitoringSchedulesTable,
|
|
71
|
+
)
|