mlrun 1.7.2rc3__py3-none-any.whl → 1.8.0__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 +26 -22
- mlrun/__main__.py +15 -16
- mlrun/alerts/alert.py +150 -15
- mlrun/api/schemas/__init__.py +1 -9
- mlrun/artifacts/__init__.py +2 -3
- mlrun/artifacts/base.py +62 -19
- mlrun/artifacts/dataset.py +17 -17
- mlrun/artifacts/document.py +454 -0
- mlrun/artifacts/manager.py +28 -18
- mlrun/artifacts/model.py +91 -59
- mlrun/artifacts/plots.py +2 -2
- mlrun/common/constants.py +8 -0
- mlrun/common/formatters/__init__.py +1 -0
- mlrun/common/formatters/artifact.py +1 -1
- mlrun/common/formatters/feature_set.py +2 -0
- mlrun/common/formatters/function.py +1 -0
- mlrun/{model_monitoring/db/stores/v3io_kv/__init__.py → common/formatters/model_endpoint.py} +17 -0
- mlrun/common/formatters/pipeline.py +1 -2
- mlrun/common/formatters/project.py +9 -0
- mlrun/common/model_monitoring/__init__.py +0 -5
- mlrun/common/model_monitoring/helpers.py +12 -62
- mlrun/common/runtimes/constants.py +25 -4
- mlrun/common/schemas/__init__.py +9 -5
- mlrun/common/schemas/alert.py +114 -19
- mlrun/common/schemas/api_gateway.py +3 -3
- mlrun/common/schemas/artifact.py +22 -9
- mlrun/common/schemas/auth.py +8 -4
- mlrun/common/schemas/background_task.py +7 -7
- mlrun/common/schemas/client_spec.py +4 -4
- mlrun/common/schemas/clusterization_spec.py +2 -2
- mlrun/common/schemas/common.py +53 -3
- mlrun/common/schemas/constants.py +15 -0
- mlrun/common/schemas/datastore_profile.py +1 -1
- mlrun/common/schemas/feature_store.py +9 -9
- mlrun/common/schemas/frontend_spec.py +4 -4
- mlrun/common/schemas/function.py +10 -10
- mlrun/common/schemas/hub.py +1 -1
- mlrun/common/schemas/k8s.py +3 -3
- mlrun/common/schemas/memory_reports.py +3 -3
- mlrun/common/schemas/model_monitoring/__init__.py +4 -8
- mlrun/common/schemas/model_monitoring/constants.py +127 -46
- mlrun/common/schemas/model_monitoring/grafana.py +18 -12
- mlrun/common/schemas/model_monitoring/model_endpoints.py +154 -160
- mlrun/common/schemas/notification.py +24 -3
- mlrun/common/schemas/object.py +1 -1
- mlrun/common/schemas/pagination.py +4 -4
- mlrun/common/schemas/partition.py +142 -0
- mlrun/common/schemas/pipeline.py +3 -3
- mlrun/common/schemas/project.py +26 -18
- mlrun/common/schemas/runs.py +3 -3
- mlrun/common/schemas/runtime_resource.py +5 -5
- mlrun/common/schemas/schedule.py +1 -1
- mlrun/common/schemas/secret.py +1 -1
- mlrun/{model_monitoring/db/stores/sqldb/__init__.py → common/schemas/serving.py} +10 -1
- mlrun/common/schemas/tag.py +3 -3
- mlrun/common/schemas/workflow.py +6 -5
- mlrun/common/types.py +1 -0
- mlrun/config.py +157 -89
- mlrun/data_types/__init__.py +5 -3
- mlrun/data_types/infer.py +13 -3
- mlrun/data_types/spark.py +2 -1
- mlrun/datastore/__init__.py +59 -18
- mlrun/datastore/alibaba_oss.py +4 -1
- mlrun/datastore/azure_blob.py +4 -1
- mlrun/datastore/base.py +19 -24
- mlrun/datastore/datastore.py +10 -4
- mlrun/datastore/datastore_profile.py +178 -45
- mlrun/datastore/dbfs_store.py +4 -1
- mlrun/datastore/filestore.py +4 -1
- mlrun/datastore/google_cloud_storage.py +4 -1
- mlrun/datastore/hdfs.py +4 -1
- mlrun/datastore/inmem.py +4 -1
- mlrun/datastore/redis.py +4 -1
- mlrun/datastore/s3.py +14 -3
- mlrun/datastore/sources.py +89 -92
- mlrun/datastore/store_resources.py +7 -4
- mlrun/datastore/storeytargets.py +51 -16
- mlrun/datastore/targets.py +38 -31
- mlrun/datastore/utils.py +87 -4
- mlrun/datastore/v3io.py +4 -1
- mlrun/datastore/vectorstore.py +291 -0
- mlrun/datastore/wasbfs/fs.py +13 -12
- mlrun/db/base.py +286 -100
- mlrun/db/httpdb.py +1562 -490
- mlrun/db/nopdb.py +250 -83
- mlrun/errors.py +6 -2
- mlrun/execution.py +194 -50
- mlrun/feature_store/__init__.py +2 -10
- mlrun/feature_store/api.py +20 -458
- mlrun/feature_store/common.py +9 -9
- mlrun/feature_store/feature_set.py +20 -18
- mlrun/feature_store/feature_vector.py +105 -479
- mlrun/feature_store/feature_vector_utils.py +466 -0
- mlrun/feature_store/retrieval/base.py +15 -11
- mlrun/feature_store/retrieval/job.py +2 -1
- mlrun/feature_store/retrieval/storey_merger.py +1 -1
- mlrun/feature_store/steps.py +3 -3
- mlrun/features.py +30 -13
- mlrun/frameworks/__init__.py +1 -2
- mlrun/frameworks/_common/__init__.py +1 -2
- mlrun/frameworks/_common/artifacts_library.py +2 -2
- mlrun/frameworks/_common/mlrun_interface.py +10 -6
- mlrun/frameworks/_common/model_handler.py +31 -31
- mlrun/frameworks/_common/producer.py +3 -1
- mlrun/frameworks/_dl_common/__init__.py +1 -2
- mlrun/frameworks/_dl_common/loggers/__init__.py +1 -2
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +4 -4
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +3 -3
- mlrun/frameworks/_ml_common/__init__.py +1 -2
- mlrun/frameworks/_ml_common/loggers/__init__.py +1 -2
- mlrun/frameworks/_ml_common/model_handler.py +21 -21
- mlrun/frameworks/_ml_common/plans/__init__.py +1 -2
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +3 -1
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
- mlrun/frameworks/auto_mlrun/__init__.py +1 -2
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +22 -15
- mlrun/frameworks/huggingface/__init__.py +1 -2
- mlrun/frameworks/huggingface/model_server.py +9 -9
- mlrun/frameworks/lgbm/__init__.py +47 -44
- mlrun/frameworks/lgbm/callbacks/__init__.py +1 -2
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -2
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -2
- mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -2
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +5 -5
- mlrun/frameworks/lgbm/model_handler.py +15 -11
- mlrun/frameworks/lgbm/model_server.py +11 -7
- mlrun/frameworks/lgbm/utils.py +2 -2
- mlrun/frameworks/onnx/__init__.py +1 -2
- mlrun/frameworks/onnx/dataset.py +3 -3
- mlrun/frameworks/onnx/mlrun_interface.py +2 -2
- mlrun/frameworks/onnx/model_handler.py +7 -5
- mlrun/frameworks/onnx/model_server.py +8 -6
- mlrun/frameworks/parallel_coordinates.py +11 -11
- mlrun/frameworks/pytorch/__init__.py +22 -23
- mlrun/frameworks/pytorch/callbacks/__init__.py +1 -2
- mlrun/frameworks/pytorch/callbacks/callback.py +2 -1
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +15 -8
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +19 -12
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +22 -15
- mlrun/frameworks/pytorch/callbacks_handler.py +36 -30
- mlrun/frameworks/pytorch/mlrun_interface.py +17 -17
- mlrun/frameworks/pytorch/model_handler.py +21 -17
- mlrun/frameworks/pytorch/model_server.py +13 -9
- mlrun/frameworks/sklearn/__init__.py +19 -18
- mlrun/frameworks/sklearn/estimator.py +2 -2
- mlrun/frameworks/sklearn/metric.py +3 -3
- mlrun/frameworks/sklearn/metrics_library.py +8 -6
- mlrun/frameworks/sklearn/mlrun_interface.py +3 -2
- mlrun/frameworks/sklearn/model_handler.py +4 -3
- mlrun/frameworks/tf_keras/__init__.py +11 -12
- mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -2
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +17 -14
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +15 -12
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +21 -18
- mlrun/frameworks/tf_keras/model_handler.py +17 -13
- mlrun/frameworks/tf_keras/model_server.py +12 -8
- mlrun/frameworks/xgboost/__init__.py +19 -18
- mlrun/frameworks/xgboost/model_handler.py +13 -9
- mlrun/k8s_utils.py +2 -5
- mlrun/launcher/base.py +3 -4
- mlrun/launcher/client.py +2 -2
- mlrun/launcher/local.py +6 -2
- mlrun/launcher/remote.py +1 -1
- mlrun/lists.py +8 -4
- mlrun/model.py +132 -46
- mlrun/model_monitoring/__init__.py +3 -5
- mlrun/model_monitoring/api.py +113 -98
- mlrun/model_monitoring/applications/__init__.py +0 -5
- mlrun/model_monitoring/applications/_application_steps.py +81 -50
- mlrun/model_monitoring/applications/base.py +467 -14
- mlrun/model_monitoring/applications/context.py +212 -134
- mlrun/model_monitoring/{db/stores/base → applications/evidently}/__init__.py +6 -2
- mlrun/model_monitoring/applications/evidently/base.py +146 -0
- mlrun/model_monitoring/applications/histogram_data_drift.py +89 -56
- mlrun/model_monitoring/applications/results.py +67 -15
- mlrun/model_monitoring/controller.py +701 -315
- mlrun/model_monitoring/db/__init__.py +0 -2
- mlrun/model_monitoring/db/_schedules.py +242 -0
- mlrun/model_monitoring/db/_stats.py +189 -0
- mlrun/model_monitoring/db/tsdb/__init__.py +33 -22
- mlrun/model_monitoring/db/tsdb/base.py +243 -49
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +76 -36
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connection.py +213 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +534 -88
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +436 -106
- mlrun/model_monitoring/helpers.py +356 -114
- mlrun/model_monitoring/stream_processing.py +190 -345
- mlrun/model_monitoring/tracking_policy.py +11 -4
- mlrun/model_monitoring/writer.py +49 -90
- mlrun/package/__init__.py +3 -6
- mlrun/package/context_handler.py +2 -2
- mlrun/package/packager.py +12 -9
- mlrun/package/packagers/__init__.py +0 -2
- mlrun/package/packagers/default_packager.py +14 -11
- mlrun/package/packagers/numpy_packagers.py +16 -7
- mlrun/package/packagers/pandas_packagers.py +18 -18
- mlrun/package/packagers/python_standard_library_packagers.py +25 -11
- mlrun/package/packagers_manager.py +35 -32
- mlrun/package/utils/__init__.py +0 -3
- mlrun/package/utils/_pickler.py +6 -6
- mlrun/platforms/__init__.py +47 -16
- mlrun/platforms/iguazio.py +4 -1
- mlrun/projects/operations.py +30 -30
- mlrun/projects/pipelines.py +116 -47
- mlrun/projects/project.py +1292 -329
- mlrun/render.py +5 -9
- mlrun/run.py +57 -14
- mlrun/runtimes/__init__.py +1 -3
- mlrun/runtimes/base.py +30 -22
- mlrun/runtimes/daskjob.py +9 -9
- mlrun/runtimes/databricks_job/databricks_runtime.py +6 -5
- mlrun/runtimes/function_reference.py +5 -2
- mlrun/runtimes/generators.py +3 -2
- mlrun/runtimes/kubejob.py +6 -7
- mlrun/runtimes/mounts.py +574 -0
- mlrun/runtimes/mpijob/__init__.py +0 -2
- mlrun/runtimes/mpijob/abstract.py +7 -6
- mlrun/runtimes/nuclio/api_gateway.py +7 -7
- mlrun/runtimes/nuclio/application/application.py +11 -13
- mlrun/runtimes/nuclio/application/reverse_proxy.go +66 -64
- mlrun/runtimes/nuclio/function.py +127 -70
- mlrun/runtimes/nuclio/serving.py +105 -37
- mlrun/runtimes/pod.py +159 -54
- mlrun/runtimes/remotesparkjob.py +3 -2
- mlrun/runtimes/sparkjob/__init__.py +0 -2
- mlrun/runtimes/sparkjob/spark3job.py +22 -12
- mlrun/runtimes/utils.py +7 -6
- mlrun/secrets.py +2 -2
- mlrun/serving/__init__.py +8 -0
- mlrun/serving/merger.py +7 -5
- mlrun/serving/remote.py +35 -22
- mlrun/serving/routers.py +186 -240
- mlrun/serving/server.py +41 -10
- mlrun/serving/states.py +432 -118
- mlrun/serving/utils.py +13 -2
- mlrun/serving/v1_serving.py +3 -2
- mlrun/serving/v2_serving.py +161 -203
- mlrun/track/__init__.py +1 -1
- mlrun/track/tracker.py +2 -2
- mlrun/track/trackers/mlflow_tracker.py +6 -5
- mlrun/utils/async_http.py +35 -22
- mlrun/utils/clones.py +7 -4
- mlrun/utils/helpers.py +511 -58
- mlrun/utils/logger.py +119 -13
- mlrun/utils/notifications/notification/__init__.py +22 -19
- mlrun/utils/notifications/notification/base.py +39 -15
- mlrun/utils/notifications/notification/console.py +6 -6
- mlrun/utils/notifications/notification/git.py +11 -11
- mlrun/utils/notifications/notification/ipython.py +10 -9
- mlrun/utils/notifications/notification/mail.py +176 -0
- mlrun/utils/notifications/notification/slack.py +16 -8
- mlrun/utils/notifications/notification/webhook.py +24 -8
- mlrun/utils/notifications/notification_pusher.py +191 -200
- mlrun/utils/regex.py +12 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/METADATA +81 -54
- mlrun-1.8.0.dist-info/RECORD +351 -0
- {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/WHEEL +1 -1
- mlrun/model_monitoring/applications/evidently_base.py +0 -137
- mlrun/model_monitoring/db/stores/__init__.py +0 -136
- mlrun/model_monitoring/db/stores/base/store.py +0 -213
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -71
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -190
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -103
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -40
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -659
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -726
- mlrun/model_monitoring/model_endpoint.py +0 -118
- mlrun-1.7.2rc3.dist-info/RECORD +0 -351
- {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info/licenses}/LICENSE +0 -0
- {mlrun-1.7.2rc3.dist-info → mlrun-1.8.0.dist-info}/top_level.txt +0 -0
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
import typing
|
|
16
15
|
from abc import ABC, abstractmethod
|
|
17
16
|
from datetime import datetime
|
|
18
|
-
from typing import Union
|
|
17
|
+
from typing import Callable, ClassVar, Literal, Optional, Union
|
|
19
18
|
|
|
20
19
|
import pandas as pd
|
|
21
|
-
import pydantic
|
|
20
|
+
import pydantic.v1
|
|
21
|
+
import v3io_frames.client
|
|
22
22
|
|
|
23
23
|
import mlrun.common.schemas.model_monitoring as mm_schemas
|
|
24
24
|
import mlrun.model_monitoring.db.tsdb.helpers
|
|
@@ -27,7 +27,7 @@ from mlrun.utils import logger
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class TSDBConnector(ABC):
|
|
30
|
-
type:
|
|
30
|
+
type: ClassVar[str]
|
|
31
31
|
|
|
32
32
|
def __init__(self, project: str) -> None:
|
|
33
33
|
"""
|
|
@@ -48,7 +48,7 @@ class TSDBConnector(ABC):
|
|
|
48
48
|
self.project = project
|
|
49
49
|
|
|
50
50
|
@abstractmethod
|
|
51
|
-
def apply_monitoring_stream_steps(self, graph) -> None:
|
|
51
|
+
def apply_monitoring_stream_steps(self, graph, **kwargs) -> None:
|
|
52
52
|
"""
|
|
53
53
|
Apply TSDB steps on the provided monitoring graph. Throughout these steps, the graph stores live data of
|
|
54
54
|
different key metric dictionaries. This data is being used by the monitoring dashboards in
|
|
@@ -80,6 +80,18 @@ class TSDBConnector(ABC):
|
|
|
80
80
|
:raise mlrun.errors.MLRunRuntimeError: If an error occurred while writing the event.
|
|
81
81
|
"""
|
|
82
82
|
|
|
83
|
+
@abstractmethod
|
|
84
|
+
def delete_tsdb_records(
|
|
85
|
+
self,
|
|
86
|
+
endpoint_ids: list[str],
|
|
87
|
+
) -> None:
|
|
88
|
+
"""
|
|
89
|
+
Delete model endpoint records from the TSDB connector.
|
|
90
|
+
:param endpoint_ids: List of model endpoint unique identifiers.
|
|
91
|
+
:param delete_timeout: The timeout in seconds to wait for the deletion to complete.
|
|
92
|
+
"""
|
|
93
|
+
pass
|
|
94
|
+
|
|
83
95
|
@abstractmethod
|
|
84
96
|
def delete_tsdb_resources(self):
|
|
85
97
|
"""
|
|
@@ -131,16 +143,17 @@ class TSDBConnector(ABC):
|
|
|
131
143
|
start: datetime,
|
|
132
144
|
end: datetime,
|
|
133
145
|
metrics: list[mm_schemas.ModelEndpointMonitoringMetric],
|
|
134
|
-
type:
|
|
135
|
-
|
|
146
|
+
type: Literal["metrics", "results"],
|
|
147
|
+
with_result_extra_data: bool,
|
|
148
|
+
) -> Union[
|
|
136
149
|
list[
|
|
137
|
-
|
|
150
|
+
Union[
|
|
138
151
|
mm_schemas.ModelEndpointMonitoringResultValues,
|
|
139
152
|
mm_schemas.ModelEndpointMonitoringMetricNoData,
|
|
140
153
|
],
|
|
141
154
|
],
|
|
142
155
|
list[
|
|
143
|
-
|
|
156
|
+
Union[
|
|
144
157
|
mm_schemas.ModelEndpointMonitoringMetricValues,
|
|
145
158
|
mm_schemas.ModelEndpointMonitoringMetricNoData,
|
|
146
159
|
],
|
|
@@ -150,11 +163,13 @@ class TSDBConnector(ABC):
|
|
|
150
163
|
Read metrics OR results from the TSDB and return as a list.
|
|
151
164
|
|
|
152
165
|
:param endpoint_id: The model endpoint identifier.
|
|
153
|
-
:param start:
|
|
154
|
-
:param end:
|
|
155
|
-
:param metrics:
|
|
156
|
-
:param type:
|
|
157
|
-
:
|
|
166
|
+
:param start: The start time of the query.
|
|
167
|
+
:param end: The end time of the query.
|
|
168
|
+
:param metrics: The list of metrics to get the values for.
|
|
169
|
+
:param type: "metrics" or "results" - the type of each item in metrics.
|
|
170
|
+
:param with_result_extra_data: Whether to include the extra data in the results, relevant only when
|
|
171
|
+
`type="results"`.
|
|
172
|
+
:return: A list of result values or a list of metric values.
|
|
158
173
|
"""
|
|
159
174
|
|
|
160
175
|
@abstractmethod
|
|
@@ -164,10 +179,10 @@ class TSDBConnector(ABC):
|
|
|
164
179
|
endpoint_id: str,
|
|
165
180
|
start: datetime,
|
|
166
181
|
end: datetime,
|
|
167
|
-
aggregation_window:
|
|
168
|
-
agg_funcs:
|
|
169
|
-
limit:
|
|
170
|
-
) ->
|
|
182
|
+
aggregation_window: Optional[str] = None,
|
|
183
|
+
agg_funcs: Optional[list[str]] = None,
|
|
184
|
+
limit: Optional[int] = None,
|
|
185
|
+
) -> Union[
|
|
171
186
|
mm_schemas.ModelEndpointMonitoringMetricValues,
|
|
172
187
|
mm_schemas.ModelEndpointMonitoringMetricNoData,
|
|
173
188
|
]:
|
|
@@ -194,9 +209,9 @@ class TSDBConnector(ABC):
|
|
|
194
209
|
def get_last_request(
|
|
195
210
|
self,
|
|
196
211
|
endpoint_ids: Union[str, list[str]],
|
|
197
|
-
start:
|
|
198
|
-
end:
|
|
199
|
-
) -> pd.DataFrame:
|
|
212
|
+
start: Optional[datetime] = None,
|
|
213
|
+
end: Optional[datetime] = None,
|
|
214
|
+
) -> Union[pd.DataFrame, dict[str, float]]:
|
|
200
215
|
"""
|
|
201
216
|
Fetches data from the predictions TSDB table and returns the most recent request
|
|
202
217
|
timestamp for each specified endpoint.
|
|
@@ -205,17 +220,20 @@ class TSDBConnector(ABC):
|
|
|
205
220
|
:param start: The start time for the query.
|
|
206
221
|
:param end: The end time for the query.
|
|
207
222
|
|
|
208
|
-
:return: A pd.DataFrame containing the columns [endpoint_id, last_request, last_latency]
|
|
209
|
-
|
|
223
|
+
:return: A pd.DataFrame containing the columns [endpoint_id, last_request, last_latency] or a dictionary
|
|
224
|
+
containing the endpoint_id as the key and the last request timestamp as the value.
|
|
225
|
+
if an endpoint has not been invoked within the specified time range, it will not appear in the result (relevant
|
|
226
|
+
only to non-v3io connector).
|
|
210
227
|
"""
|
|
211
228
|
|
|
212
229
|
@abstractmethod
|
|
213
230
|
def get_drift_status(
|
|
214
231
|
self,
|
|
215
232
|
endpoint_ids: Union[str, list[str]],
|
|
216
|
-
start:
|
|
217
|
-
end:
|
|
218
|
-
|
|
233
|
+
start: Optional[datetime] = None,
|
|
234
|
+
end: Optional[datetime] = None,
|
|
235
|
+
get_raw: bool = False,
|
|
236
|
+
) -> Union[pd.DataFrame, list[v3io_frames.client.RawFrame]]:
|
|
219
237
|
"""
|
|
220
238
|
Fetches data from the app-results TSDB table and returns the highest status among all
|
|
221
239
|
the result in the provided time range, which by default is the last 24 hours, for each specified endpoint.
|
|
@@ -223,6 +241,8 @@ class TSDBConnector(ABC):
|
|
|
223
241
|
:param endpoint_ids: A list of model endpoint identifiers.
|
|
224
242
|
:param start: The start time for the query.
|
|
225
243
|
:param end: The end time for the query.
|
|
244
|
+
:param get_raw: Whether to return the request as raw frames rather than a pandas dataframe. Defaults
|
|
245
|
+
to False. This can greatly improve performance when a dataframe isn't needed.
|
|
226
246
|
|
|
227
247
|
:return: A pd.DataFrame containing the columns [result_status, endpoint_id].
|
|
228
248
|
If an endpoint has not been monitored within the specified time range (last 24 hours),
|
|
@@ -232,14 +252,14 @@ class TSDBConnector(ABC):
|
|
|
232
252
|
@abstractmethod
|
|
233
253
|
def get_metrics_metadata(
|
|
234
254
|
self,
|
|
235
|
-
endpoint_id: str,
|
|
236
|
-
start:
|
|
237
|
-
end:
|
|
255
|
+
endpoint_id: Union[str, list[str]],
|
|
256
|
+
start: Optional[datetime] = None,
|
|
257
|
+
end: Optional[datetime] = None,
|
|
238
258
|
) -> pd.DataFrame:
|
|
239
259
|
"""
|
|
240
|
-
Fetches distinct metrics metadata from the metrics TSDB table for a specified model
|
|
260
|
+
Fetches distinct metrics metadata from the metrics TSDB table for a specified model endpoints.
|
|
241
261
|
|
|
242
|
-
:param endpoint_id: The model endpoint identifier.
|
|
262
|
+
:param endpoint_id: The model endpoint identifier. Can be a single id or a list of ids.
|
|
243
263
|
:param start: The start time of the query.
|
|
244
264
|
:param end: The end time of the query.
|
|
245
265
|
|
|
@@ -250,14 +270,14 @@ class TSDBConnector(ABC):
|
|
|
250
270
|
@abstractmethod
|
|
251
271
|
def get_results_metadata(
|
|
252
272
|
self,
|
|
253
|
-
endpoint_id: str,
|
|
254
|
-
start:
|
|
255
|
-
end:
|
|
273
|
+
endpoint_id: Union[str, list[str]],
|
|
274
|
+
start: Optional[datetime] = None,
|
|
275
|
+
end: Optional[datetime] = None,
|
|
256
276
|
) -> pd.DataFrame:
|
|
257
277
|
"""
|
|
258
|
-
Fetches distinct results metadata from the app-results TSDB table for a specified model
|
|
278
|
+
Fetches distinct results metadata from the app-results TSDB table for a specified model endpoints.
|
|
259
279
|
|
|
260
|
-
:param endpoint_id: The model endpoint identifier.
|
|
280
|
+
:param endpoint_id: The model endpoint identifier. Can be a single id or a list of ids.
|
|
261
281
|
:param start: The start time of the query.
|
|
262
282
|
:param end: The end time of the query.
|
|
263
283
|
|
|
@@ -269,15 +289,18 @@ class TSDBConnector(ABC):
|
|
|
269
289
|
def get_error_count(
|
|
270
290
|
self,
|
|
271
291
|
endpoint_ids: Union[str, list[str]],
|
|
272
|
-
start:
|
|
273
|
-
end:
|
|
274
|
-
|
|
292
|
+
start: Optional[datetime] = None,
|
|
293
|
+
end: Optional[datetime] = None,
|
|
294
|
+
get_raw: bool = False,
|
|
295
|
+
) -> Union[pd.DataFrame, list[v3io_frames.client.RawFrame]]:
|
|
275
296
|
"""
|
|
276
297
|
Fetches data from the error TSDB table and returns the error count for each specified endpoint.
|
|
277
298
|
|
|
278
299
|
:param endpoint_ids: A list of model endpoint identifiers.
|
|
279
300
|
:param start: The start time for the query.
|
|
280
301
|
:param end: The end time for the query.
|
|
302
|
+
:param get_raw: Whether to return the request as raw frames rather than a pandas dataframe. Defaults
|
|
303
|
+
to False. This can greatly improve performance when a dataframe isn't needed.
|
|
281
304
|
|
|
282
305
|
:return: A pd.DataFrame containing the columns [error_count, endpoint_id].
|
|
283
306
|
If an endpoint have not raised error within the specified time range, it will not appear in the result.
|
|
@@ -287,20 +310,33 @@ class TSDBConnector(ABC):
|
|
|
287
310
|
def get_avg_latency(
|
|
288
311
|
self,
|
|
289
312
|
endpoint_ids: Union[str, list[str]],
|
|
290
|
-
start:
|
|
291
|
-
end:
|
|
292
|
-
|
|
313
|
+
start: Optional[datetime] = None,
|
|
314
|
+
end: Optional[datetime] = None,
|
|
315
|
+
get_raw: bool = False,
|
|
316
|
+
) -> Union[pd.DataFrame, list[v3io_frames.client.RawFrame]]:
|
|
293
317
|
"""
|
|
294
318
|
Fetches data from the predictions TSDB table and returns the average latency for each specified endpoint
|
|
319
|
+
in the provided time range, which by default is the last 24 hours.
|
|
295
320
|
|
|
296
321
|
:param endpoint_ids: A list of model endpoint identifiers.
|
|
297
322
|
:param start: The start time for the query.
|
|
298
323
|
:param end: The end time for the query.
|
|
324
|
+
:param get_raw: Whether to return the request as raw frames rather than a pandas dataframe. Defaults
|
|
325
|
+
to False. This can greatly improve performance when a dataframe isn't needed.
|
|
299
326
|
|
|
300
327
|
:return: A pd.DataFrame containing the columns [avg_latency, endpoint_id].
|
|
301
328
|
If an endpoint has not been invoked within the specified time range, it will not appear in the result.
|
|
302
329
|
"""
|
|
303
330
|
|
|
331
|
+
async def add_basic_metrics(
|
|
332
|
+
self,
|
|
333
|
+
model_endpoint_objects: list[mlrun.common.schemas.ModelEndpoint],
|
|
334
|
+
project: str,
|
|
335
|
+
run_in_threadpool: Callable,
|
|
336
|
+
metric_list: Optional[list[str]] = None,
|
|
337
|
+
) -> list[mlrun.common.schemas.ModelEndpoint]:
|
|
338
|
+
raise NotImplementedError()
|
|
339
|
+
|
|
304
340
|
@staticmethod
|
|
305
341
|
def df_to_metrics_values(
|
|
306
342
|
*,
|
|
@@ -308,7 +344,7 @@ class TSDBConnector(ABC):
|
|
|
308
344
|
metrics: list[mm_schemas.ModelEndpointMonitoringMetric],
|
|
309
345
|
project: str,
|
|
310
346
|
) -> list[
|
|
311
|
-
|
|
347
|
+
Union[
|
|
312
348
|
mm_schemas.ModelEndpointMonitoringMetricValues,
|
|
313
349
|
mm_schemas.ModelEndpointMonitoringMetricNoData,
|
|
314
350
|
]
|
|
@@ -321,7 +357,7 @@ class TSDBConnector(ABC):
|
|
|
321
357
|
metrics_without_data = {metric.full_name: metric for metric in metrics}
|
|
322
358
|
|
|
323
359
|
metrics_values: list[
|
|
324
|
-
|
|
360
|
+
Union[
|
|
325
361
|
mm_schemas.ModelEndpointMonitoringMetricValues,
|
|
326
362
|
mm_schemas.ModelEndpointMonitoringMetricNoData,
|
|
327
363
|
]
|
|
@@ -338,7 +374,7 @@ class TSDBConnector(ABC):
|
|
|
338
374
|
logger.debug("No metrics", missing_metrics=metrics_without_data.keys())
|
|
339
375
|
grouped = []
|
|
340
376
|
for (app_name, name), sub_df in grouped:
|
|
341
|
-
full_name =
|
|
377
|
+
full_name = mm_schemas.model_endpoints.compose_full_name(
|
|
342
378
|
project=project,
|
|
343
379
|
app=app_name,
|
|
344
380
|
name=name,
|
|
@@ -374,7 +410,7 @@ class TSDBConnector(ABC):
|
|
|
374
410
|
metrics: list[mm_schemas.ModelEndpointMonitoringMetric],
|
|
375
411
|
project: str,
|
|
376
412
|
) -> list[
|
|
377
|
-
|
|
413
|
+
Union[
|
|
378
414
|
mm_schemas.ModelEndpointMonitoringResultValues,
|
|
379
415
|
mm_schemas.ModelEndpointMonitoringMetricNoData,
|
|
380
416
|
]
|
|
@@ -387,7 +423,7 @@ class TSDBConnector(ABC):
|
|
|
387
423
|
metrics_without_data = {metric.full_name: metric for metric in metrics}
|
|
388
424
|
|
|
389
425
|
metrics_values: list[
|
|
390
|
-
|
|
426
|
+
Union[
|
|
391
427
|
mm_schemas.ModelEndpointMonitoringResultValues,
|
|
392
428
|
mm_schemas.ModelEndpointMonitoringMetricNoData,
|
|
393
429
|
]
|
|
@@ -407,7 +443,7 @@ class TSDBConnector(ABC):
|
|
|
407
443
|
result_kind = mlrun.model_monitoring.db.tsdb.helpers._get_result_kind(
|
|
408
444
|
sub_df
|
|
409
445
|
)
|
|
410
|
-
full_name =
|
|
446
|
+
full_name = mm_schemas.model_endpoints.compose_full_name(
|
|
411
447
|
project=project, app=app_name, name=name
|
|
412
448
|
)
|
|
413
449
|
try:
|
|
@@ -420,11 +456,12 @@ class TSDBConnector(ABC):
|
|
|
420
456
|
sub_df.index,
|
|
421
457
|
sub_df[mm_schemas.ResultData.RESULT_VALUE],
|
|
422
458
|
sub_df[mm_schemas.ResultData.RESULT_STATUS],
|
|
459
|
+
sub_df[mm_schemas.ResultData.RESULT_EXTRA_DATA],
|
|
423
460
|
)
|
|
424
461
|
), # pyright: ignore[reportArgumentType]
|
|
425
462
|
)
|
|
426
463
|
)
|
|
427
|
-
except pydantic.ValidationError:
|
|
464
|
+
except pydantic.v1.ValidationError:
|
|
428
465
|
logger.exception(
|
|
429
466
|
"Failed to convert data-frame into `ModelEndpointMonitoringResultValues`",
|
|
430
467
|
full_name=full_name,
|
|
@@ -446,3 +483,160 @@ class TSDBConnector(ABC):
|
|
|
446
483
|
)
|
|
447
484
|
|
|
448
485
|
return metrics_values
|
|
486
|
+
|
|
487
|
+
@staticmethod
|
|
488
|
+
def df_to_metrics_list(
|
|
489
|
+
*,
|
|
490
|
+
df: pd.DataFrame,
|
|
491
|
+
project: str,
|
|
492
|
+
type: str,
|
|
493
|
+
) -> list[mm_schemas.ModelEndpointMonitoringMetric]:
|
|
494
|
+
"""
|
|
495
|
+
Parse a DataFrame of metrics from the TSDB into a list of mm metrics objects.
|
|
496
|
+
|
|
497
|
+
:param df: The DataFrame to parse.
|
|
498
|
+
:param project: The project name.
|
|
499
|
+
:param type: The type of the metrics (either "result" or "metric").
|
|
500
|
+
|
|
501
|
+
:return: A list of mm metrics objects.
|
|
502
|
+
"""
|
|
503
|
+
|
|
504
|
+
return list(
|
|
505
|
+
map(
|
|
506
|
+
lambda record: mm_schemas.ModelEndpointMonitoringMetric(
|
|
507
|
+
project=project,
|
|
508
|
+
type=type,
|
|
509
|
+
app=record.get(mm_schemas.WriterEvent.APPLICATION_NAME),
|
|
510
|
+
name=record.get(mm_schemas.ResultData.RESULT_NAME)
|
|
511
|
+
or record.get(mm_schemas.MetricData.METRIC_NAME),
|
|
512
|
+
kind=record.get(mm_schemas.ResultData.RESULT_KIND),
|
|
513
|
+
),
|
|
514
|
+
df.to_dict("records"),
|
|
515
|
+
)
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
@staticmethod
|
|
519
|
+
def df_to_metrics_grouped_dict(
|
|
520
|
+
*,
|
|
521
|
+
df: pd.DataFrame,
|
|
522
|
+
project: str,
|
|
523
|
+
type: str,
|
|
524
|
+
) -> dict[str, list[mm_schemas.ModelEndpointMonitoringMetric]]:
|
|
525
|
+
"""
|
|
526
|
+
Parse a DataFrame of metrics from the TSDB into a grouped mm metrics objects by endpoint_id.
|
|
527
|
+
|
|
528
|
+
:param df: The DataFrame to parse.
|
|
529
|
+
:param project: The project name.
|
|
530
|
+
:param type: The type of the metrics (either "result" or "metric").
|
|
531
|
+
|
|
532
|
+
:return: A grouped dict of mm metrics/results, using model_endpoints_ids as keys.
|
|
533
|
+
"""
|
|
534
|
+
|
|
535
|
+
if df.empty:
|
|
536
|
+
return {}
|
|
537
|
+
|
|
538
|
+
grouped_by_fields = [mm_schemas.WriterEvent.APPLICATION_NAME]
|
|
539
|
+
if type == "result":
|
|
540
|
+
name_column = mm_schemas.ResultData.RESULT_NAME
|
|
541
|
+
grouped_by_fields.append(mm_schemas.ResultData.RESULT_KIND)
|
|
542
|
+
else:
|
|
543
|
+
name_column = mm_schemas.MetricData.METRIC_NAME
|
|
544
|
+
|
|
545
|
+
grouped_by_fields.append(name_column)
|
|
546
|
+
# groupby has different behavior for category columns
|
|
547
|
+
df["endpoint_id"] = df["endpoint_id"].astype(str)
|
|
548
|
+
grouped_by_df = df.groupby("endpoint_id")
|
|
549
|
+
grouped_dict = grouped_by_df.apply(
|
|
550
|
+
lambda group: list(
|
|
551
|
+
map(
|
|
552
|
+
lambda record: mm_schemas.ModelEndpointMonitoringMetric(
|
|
553
|
+
project=project,
|
|
554
|
+
type=type,
|
|
555
|
+
app=record.get(mm_schemas.WriterEvent.APPLICATION_NAME),
|
|
556
|
+
name=record.get(name_column),
|
|
557
|
+
**{"kind": record.get(mm_schemas.ResultData.RESULT_KIND)}
|
|
558
|
+
if type == "result"
|
|
559
|
+
else {},
|
|
560
|
+
),
|
|
561
|
+
group[grouped_by_fields].to_dict(orient="records"),
|
|
562
|
+
)
|
|
563
|
+
)
|
|
564
|
+
).to_dict()
|
|
565
|
+
return grouped_dict
|
|
566
|
+
|
|
567
|
+
@staticmethod
|
|
568
|
+
def df_to_events_intersection_dict(
|
|
569
|
+
*,
|
|
570
|
+
df: pd.DataFrame,
|
|
571
|
+
project: str,
|
|
572
|
+
type: Union[str, mm_schemas.ModelEndpointMonitoringMetricType],
|
|
573
|
+
) -> dict[str, list[mm_schemas.ModelEndpointMonitoringMetric]]:
|
|
574
|
+
"""
|
|
575
|
+
Parse a DataFrame of metrics from the TSDB into a dict of intersection metrics/results by name and application
|
|
576
|
+
(and kind in results).
|
|
577
|
+
|
|
578
|
+
:param df: The DataFrame to parse.
|
|
579
|
+
:param project: The project name.
|
|
580
|
+
:param type: The type of the metrics (either "result" or "metric").
|
|
581
|
+
|
|
582
|
+
:return: A dictionary where the key is event type (as defined by `INTERSECT_DICT_KEYS`),
|
|
583
|
+
and the value is a list containing the intersect metrics or results across all endpoint IDs.
|
|
584
|
+
|
|
585
|
+
For example:
|
|
586
|
+
{
|
|
587
|
+
"intersect_metrics": [...]
|
|
588
|
+
}
|
|
589
|
+
"""
|
|
590
|
+
dict_key = mm_schemas.INTERSECT_DICT_KEYS[type]
|
|
591
|
+
metrics = []
|
|
592
|
+
if df.empty:
|
|
593
|
+
return {dict_key: []}
|
|
594
|
+
|
|
595
|
+
columns_to_zip = [mm_schemas.WriterEvent.APPLICATION_NAME]
|
|
596
|
+
|
|
597
|
+
if type == "result":
|
|
598
|
+
name_column = mm_schemas.ResultData.RESULT_NAME
|
|
599
|
+
columns_to_zip.append(mm_schemas.ResultData.RESULT_KIND)
|
|
600
|
+
else:
|
|
601
|
+
name_column = mm_schemas.MetricData.METRIC_NAME
|
|
602
|
+
columns_to_zip.insert(1, name_column)
|
|
603
|
+
|
|
604
|
+
# groupby has different behavior for category columns
|
|
605
|
+
df["endpoint_id"] = df["endpoint_id"].astype(str)
|
|
606
|
+
df["event_values"] = list(zip(*[df[col] for col in columns_to_zip]))
|
|
607
|
+
grouped_by_event_values = df.groupby("endpoint_id")["event_values"].apply(set)
|
|
608
|
+
common_event_values_combinations = set.intersection(*grouped_by_event_values)
|
|
609
|
+
result_kind = None
|
|
610
|
+
for data in common_event_values_combinations:
|
|
611
|
+
application_name, event_name = data[0], data[1]
|
|
612
|
+
if len(data) > 2: # in result case
|
|
613
|
+
result_kind = data[2]
|
|
614
|
+
metrics.append(
|
|
615
|
+
mm_schemas.ModelEndpointMonitoringMetric(
|
|
616
|
+
project=project,
|
|
617
|
+
type=type,
|
|
618
|
+
app=application_name,
|
|
619
|
+
name=event_name,
|
|
620
|
+
kind=result_kind,
|
|
621
|
+
)
|
|
622
|
+
)
|
|
623
|
+
return {dict_key: metrics}
|
|
624
|
+
|
|
625
|
+
@staticmethod
|
|
626
|
+
def _get_start_end(
|
|
627
|
+
start: Union[datetime, None],
|
|
628
|
+
end: Union[datetime, None],
|
|
629
|
+
) -> tuple[datetime, datetime]:
|
|
630
|
+
"""
|
|
631
|
+
static utils function for tsdb start end format
|
|
632
|
+
:param start: Either None or datetime, None is handled as datetime.min(tz=timezone.utc)
|
|
633
|
+
:param end: Either None or datetime, None is handled as datetime.now(tz=timezone.utc)
|
|
634
|
+
:return: start datetime, end datetime
|
|
635
|
+
"""
|
|
636
|
+
start = start or mlrun.utils.datetime_min()
|
|
637
|
+
end = end or mlrun.utils.datetime_now()
|
|
638
|
+
if not (isinstance(start, datetime) and isinstance(end, datetime)):
|
|
639
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
640
|
+
"Both start and end must be datetime objects"
|
|
641
|
+
)
|
|
642
|
+
return start, end
|
|
@@ -26,7 +26,7 @@ _MODEL_MONITORING_DATABASE = "mlrun_model_monitoring"
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class _TDEngineColumnType:
|
|
29
|
-
def __init__(self, data_type: str, length: int = None):
|
|
29
|
+
def __init__(self, data_type: str, length: Optional[int] = None):
|
|
30
30
|
self.data_type = data_type
|
|
31
31
|
self.length = length
|
|
32
32
|
|
|
@@ -46,7 +46,7 @@ class _TDEngineColumn(mlrun.common.types.StrEnum):
|
|
|
46
46
|
INT = _TDEngineColumnType("INT")
|
|
47
47
|
BINARY_40 = _TDEngineColumnType("BINARY", 40)
|
|
48
48
|
BINARY_64 = _TDEngineColumnType("BINARY", 64)
|
|
49
|
-
|
|
49
|
+
BINARY_1000 = _TDEngineColumnType("BINARY", 1000)
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def values_to_column(values, column_type):
|
|
@@ -61,7 +61,7 @@ def values_to_column(values, column_type):
|
|
|
61
61
|
return taosws.binary_to_column(values)
|
|
62
62
|
if column_type == _TDEngineColumn.BINARY_64:
|
|
63
63
|
return taosws.binary_to_column(values)
|
|
64
|
-
if column_type == _TDEngineColumn.
|
|
64
|
+
if column_type == _TDEngineColumn.BINARY_1000:
|
|
65
65
|
return taosws.binary_to_column(values)
|
|
66
66
|
|
|
67
67
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
@@ -108,27 +108,6 @@ class TDEngineSchema:
|
|
|
108
108
|
)
|
|
109
109
|
return f"CREATE TABLE if NOT EXISTS {self.database}.{subtable} USING {self.super_table} TAGS ({tags});"
|
|
110
110
|
|
|
111
|
-
@staticmethod
|
|
112
|
-
def _insert_subtable_stmt(
|
|
113
|
-
statement: taosws.TaosStmt,
|
|
114
|
-
columns: dict[str, _TDEngineColumn],
|
|
115
|
-
subtable: str,
|
|
116
|
-
values: dict[str, Union[str, int, float, datetime.datetime]],
|
|
117
|
-
) -> taosws.TaosStmt:
|
|
118
|
-
question_marks = ", ".join("?" * len(columns))
|
|
119
|
-
statement.prepare(f"INSERT INTO ? VALUES ({question_marks});")
|
|
120
|
-
statement.set_tbname(subtable)
|
|
121
|
-
|
|
122
|
-
bind_params = []
|
|
123
|
-
|
|
124
|
-
for col_name, col_type in columns.items():
|
|
125
|
-
val = values[col_name]
|
|
126
|
-
bind_params.append(values_to_column([val], col_type))
|
|
127
|
-
|
|
128
|
-
statement.bind_param(bind_params)
|
|
129
|
-
statement.add_batch()
|
|
130
|
-
return statement
|
|
131
|
-
|
|
132
111
|
def _delete_subtable_query(
|
|
133
112
|
self,
|
|
134
113
|
subtable: str,
|
|
@@ -143,26 +122,30 @@ class TDEngineSchema:
|
|
|
143
122
|
)
|
|
144
123
|
return f"DELETE FROM {self.database}.{subtable} WHERE {values};"
|
|
145
124
|
|
|
146
|
-
def
|
|
125
|
+
def drop_subtable_query(
|
|
147
126
|
self,
|
|
148
127
|
subtable: str,
|
|
149
128
|
) -> str:
|
|
150
|
-
return f"DROP TABLE if EXISTS {self.database}
|
|
129
|
+
return f"DROP TABLE if EXISTS {self.database}.`{subtable}`;"
|
|
151
130
|
|
|
152
131
|
def drop_supertable_query(self) -> str:
|
|
153
132
|
return f"DROP STABLE if EXISTS {self.database}.{self.super_table};"
|
|
154
133
|
|
|
155
|
-
def
|
|
134
|
+
def _get_subtables_query_by_tag(
|
|
156
135
|
self,
|
|
157
|
-
|
|
136
|
+
filter_tag: str,
|
|
137
|
+
filter_values: list[str],
|
|
138
|
+
operator: str = "OR",
|
|
158
139
|
) -> str:
|
|
159
|
-
|
|
160
|
-
f"{val} LIKE '{values[val]}'" for val in self.tags if val in values
|
|
161
|
-
)
|
|
162
|
-
if not values:
|
|
140
|
+
if filter_tag not in self.tags:
|
|
163
141
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
164
|
-
f"
|
|
142
|
+
f"`filter_tag` must be one of the tags: {self.tags.keys()}"
|
|
165
143
|
)
|
|
144
|
+
|
|
145
|
+
values = f" {operator} ".join(
|
|
146
|
+
f"{filter_tag} LIKE '{val}'" for val in filter_values
|
|
147
|
+
)
|
|
148
|
+
|
|
166
149
|
return f"SELECT DISTINCT tbname FROM {self.database}.{self.super_table} WHERE {values};"
|
|
167
150
|
|
|
168
151
|
@staticmethod
|
|
@@ -170,7 +153,7 @@ class TDEngineSchema:
|
|
|
170
153
|
table: str,
|
|
171
154
|
start: datetime.datetime,
|
|
172
155
|
end: datetime.datetime,
|
|
173
|
-
columns_to_filter: list[str] = None,
|
|
156
|
+
columns_to_filter: Optional[list[str]] = None,
|
|
174
157
|
filter_query: Optional[str] = None,
|
|
175
158
|
interval: Optional[str] = None,
|
|
176
159
|
limit: int = 0,
|
|
@@ -178,6 +161,10 @@ class TDEngineSchema:
|
|
|
178
161
|
sliding_window_step: Optional[str] = None,
|
|
179
162
|
timestamp_column: str = "time",
|
|
180
163
|
database: str = _MODEL_MONITORING_DATABASE,
|
|
164
|
+
group_by: Optional[Union[list[str], str]] = None,
|
|
165
|
+
preform_agg_funcs_columns: Optional[list[str]] = None,
|
|
166
|
+
order_by: Optional[str] = None,
|
|
167
|
+
desc: Optional[bool] = None,
|
|
181
168
|
) -> str:
|
|
182
169
|
if agg_funcs and not columns_to_filter:
|
|
183
170
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
@@ -194,15 +181,37 @@ class TDEngineSchema:
|
|
|
194
181
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
195
182
|
"`interval` must be provided when using sliding window"
|
|
196
183
|
)
|
|
184
|
+
if group_by and not agg_funcs:
|
|
185
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
186
|
+
"aggregate functions must be provided when using group by"
|
|
187
|
+
)
|
|
188
|
+
if desc and not order_by:
|
|
189
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
190
|
+
"`order_by` must be provided when using descending"
|
|
191
|
+
)
|
|
197
192
|
|
|
198
193
|
with StringIO() as query:
|
|
199
194
|
query.write("SELECT ")
|
|
200
195
|
if interval:
|
|
201
196
|
query.write("_wstart, _wend, ")
|
|
202
197
|
if agg_funcs:
|
|
198
|
+
preform_agg_funcs_columns = (
|
|
199
|
+
columns_to_filter
|
|
200
|
+
if preform_agg_funcs_columns is None
|
|
201
|
+
else preform_agg_funcs_columns
|
|
202
|
+
)
|
|
203
203
|
query.write(
|
|
204
204
|
", ".join(
|
|
205
|
-
[
|
|
205
|
+
[
|
|
206
|
+
f"{a}({col})"
|
|
207
|
+
if col.upper()
|
|
208
|
+
in map(
|
|
209
|
+
str.upper, preform_agg_funcs_columns
|
|
210
|
+
) # Case-insensitive check
|
|
211
|
+
else f"{col}"
|
|
212
|
+
for a in agg_funcs
|
|
213
|
+
for col in columns_to_filter
|
|
214
|
+
]
|
|
206
215
|
)
|
|
207
216
|
)
|
|
208
217
|
elif columns_to_filter:
|
|
@@ -219,6 +228,13 @@ class TDEngineSchema:
|
|
|
219
228
|
query.write(f"{timestamp_column} >= '{start}' AND ")
|
|
220
229
|
if end:
|
|
221
230
|
query.write(f"{timestamp_column} <= '{end}'")
|
|
231
|
+
if group_by:
|
|
232
|
+
if isinstance(group_by, list):
|
|
233
|
+
group_by = ", ".join(group_by)
|
|
234
|
+
query.write(f" GROUP BY {group_by}")
|
|
235
|
+
if order_by:
|
|
236
|
+
desc = " DESC" if desc else ""
|
|
237
|
+
query.write(f" ORDER BY {order_by}{desc}")
|
|
222
238
|
if interval:
|
|
223
239
|
query.write(f" INTERVAL({interval})")
|
|
224
240
|
if sliding_window_step:
|
|
@@ -238,6 +254,7 @@ class AppResultTable(TDEngineSchema):
|
|
|
238
254
|
mm_schemas.WriterEvent.START_INFER_TIME: _TDEngineColumn.TIMESTAMP,
|
|
239
255
|
mm_schemas.ResultData.RESULT_VALUE: _TDEngineColumn.FLOAT,
|
|
240
256
|
mm_schemas.ResultData.RESULT_STATUS: _TDEngineColumn.INT,
|
|
257
|
+
mm_schemas.ResultData.RESULT_EXTRA_DATA: _TDEngineColumn.BINARY_1000,
|
|
241
258
|
}
|
|
242
259
|
tags = {
|
|
243
260
|
mm_schemas.WriterEvent.ENDPOINT_ID: _TDEngineColumn.BINARY_64,
|
|
@@ -284,10 +301,33 @@ class Predictions(TDEngineSchema):
|
|
|
284
301
|
columns = {
|
|
285
302
|
mm_schemas.EventFieldType.TIME: _TDEngineColumn.TIMESTAMP,
|
|
286
303
|
mm_schemas.EventFieldType.LATENCY: _TDEngineColumn.FLOAT,
|
|
287
|
-
mm_schemas.EventKeyMetrics.CUSTOM_METRICS: _TDEngineColumn.
|
|
304
|
+
mm_schemas.EventKeyMetrics.CUSTOM_METRICS: _TDEngineColumn.BINARY_1000,
|
|
305
|
+
mm_schemas.EventFieldType.ESTIMATED_PREDICTION_COUNT: _TDEngineColumn.FLOAT,
|
|
306
|
+
mm_schemas.EventFieldType.EFFECTIVE_SAMPLE_COUNT: _TDEngineColumn.INT,
|
|
307
|
+
}
|
|
308
|
+
tags = {
|
|
309
|
+
mm_schemas.WriterEvent.ENDPOINT_ID: _TDEngineColumn.BINARY_64,
|
|
310
|
+
}
|
|
311
|
+
super().__init__(
|
|
312
|
+
super_table=super_table,
|
|
313
|
+
columns=columns,
|
|
314
|
+
tags=tags,
|
|
315
|
+
database=database,
|
|
316
|
+
project=project,
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
@dataclass
|
|
321
|
+
class Errors(TDEngineSchema):
|
|
322
|
+
def __init__(self, project: str, database: Optional[str] = None):
|
|
323
|
+
super_table = mm_schemas.TDEngineSuperTables.ERRORS
|
|
324
|
+
columns = {
|
|
325
|
+
mm_schemas.EventFieldType.TIME: _TDEngineColumn.TIMESTAMP,
|
|
326
|
+
mm_schemas.EventFieldType.MODEL_ERROR: _TDEngineColumn.BINARY_1000,
|
|
288
327
|
}
|
|
289
328
|
tags = {
|
|
290
329
|
mm_schemas.WriterEvent.ENDPOINT_ID: _TDEngineColumn.BINARY_64,
|
|
330
|
+
mm_schemas.EventFieldType.ERROR_TYPE: _TDEngineColumn.BINARY_64,
|
|
291
331
|
}
|
|
292
332
|
super().__init__(
|
|
293
333
|
super_table=super_table,
|