mlrun 1.8.0rc5__py3-none-any.whl → 1.8.0rc7__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 +1 -0
- mlrun/artifacts/__init__.py +1 -1
- mlrun/artifacts/base.py +12 -1
- mlrun/artifacts/document.py +59 -38
- mlrun/common/constants.py +1 -0
- mlrun/common/model_monitoring/__init__.py +0 -2
- mlrun/common/model_monitoring/helpers.py +0 -28
- mlrun/common/schemas/__init__.py +2 -4
- mlrun/common/schemas/alert.py +77 -1
- mlrun/common/schemas/client_spec.py +0 -1
- mlrun/common/schemas/model_monitoring/__init__.py +0 -6
- mlrun/common/schemas/model_monitoring/constants.py +11 -9
- mlrun/common/schemas/model_monitoring/model_endpoints.py +77 -149
- mlrun/common/schemas/notification.py +6 -0
- mlrun/common/schemas/project.py +3 -0
- mlrun/config.py +2 -3
- mlrun/datastore/datastore_profile.py +57 -17
- mlrun/datastore/sources.py +1 -2
- mlrun/datastore/vectorstore.py +67 -59
- mlrun/db/base.py +29 -19
- mlrun/db/httpdb.py +218 -159
- mlrun/db/nopdb.py +36 -17
- mlrun/execution.py +14 -7
- mlrun/feature_store/api.py +1 -0
- mlrun/model.py +3 -0
- mlrun/model_monitoring/__init__.py +3 -2
- mlrun/model_monitoring/api.py +55 -53
- mlrun/model_monitoring/applications/_application_steps.py +3 -1
- mlrun/model_monitoring/applications/base.py +115 -15
- mlrun/model_monitoring/applications/context.py +42 -24
- mlrun/model_monitoring/applications/histogram_data_drift.py +1 -1
- mlrun/model_monitoring/controller.py +43 -37
- mlrun/model_monitoring/db/__init__.py +0 -2
- mlrun/model_monitoring/db/tsdb/base.py +2 -1
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +2 -1
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +43 -0
- mlrun/model_monitoring/helpers.py +79 -66
- mlrun/model_monitoring/stream_processing.py +83 -270
- mlrun/model_monitoring/writer.py +1 -10
- mlrun/projects/pipelines.py +37 -1
- mlrun/projects/project.py +147 -55
- mlrun/run.py +40 -0
- mlrun/runtimes/nuclio/function.py +7 -6
- mlrun/runtimes/nuclio/serving.py +9 -2
- mlrun/serving/routers.py +158 -145
- mlrun/serving/server.py +6 -0
- mlrun/serving/states.py +21 -7
- mlrun/serving/v2_serving.py +70 -61
- mlrun/utils/helpers.py +14 -30
- mlrun/utils/notifications/notification/mail.py +17 -6
- mlrun/utils/notifications/notification_pusher.py +9 -5
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc7.dist-info}/METADATA +2 -2
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc7.dist-info}/RECORD +58 -71
- mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +0 -149
- mlrun/model_monitoring/db/stores/__init__.py +0 -136
- mlrun/model_monitoring/db/stores/base/__init__.py +0 -15
- mlrun/model_monitoring/db/stores/base/store.py +0 -154
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -46
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -93
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -47
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -25
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -408
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -464
- mlrun/model_monitoring/model_endpoint.py +0 -120
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc7.dist-info}/LICENSE +0 -0
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc7.dist-info}/WHEEL +0 -0
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc7.dist-info}/entry_points.txt +0 -0
- {mlrun-1.8.0rc5.dist-info → mlrun-1.8.0rc7.dist-info}/top_level.txt +0 -0
|
@@ -24,6 +24,9 @@ if typing.TYPE_CHECKING:
|
|
|
24
24
|
from mlrun.db.base import RunDBInterface
|
|
25
25
|
from mlrun.projects import MlrunProject
|
|
26
26
|
|
|
27
|
+
from fnmatch import fnmatchcase
|
|
28
|
+
from typing import Optional
|
|
29
|
+
|
|
27
30
|
import mlrun
|
|
28
31
|
import mlrun.artifacts
|
|
29
32
|
import mlrun.common.model_monitoring.helpers
|
|
@@ -31,11 +34,11 @@ import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
|
31
34
|
import mlrun.data_types.infer
|
|
32
35
|
import mlrun.model_monitoring
|
|
33
36
|
import mlrun.utils.helpers
|
|
37
|
+
from mlrun.common.schemas import ModelEndpoint
|
|
34
38
|
from mlrun.common.schemas.model_monitoring.model_endpoints import (
|
|
35
39
|
ModelEndpointMonitoringMetric,
|
|
36
40
|
_compose_full_name,
|
|
37
41
|
)
|
|
38
|
-
from mlrun.model_monitoring.model_endpoint import ModelEndpoint
|
|
39
42
|
from mlrun.utils import logger
|
|
40
43
|
|
|
41
44
|
|
|
@@ -45,6 +48,70 @@ class _BatchDict(typing.TypedDict):
|
|
|
45
48
|
days: int
|
|
46
49
|
|
|
47
50
|
|
|
51
|
+
def _is_results_regex_match(
|
|
52
|
+
existing_result_name: Optional[str],
|
|
53
|
+
result_name_filters: Optional[list[str]],
|
|
54
|
+
) -> bool:
|
|
55
|
+
if existing_result_name.count(".") != 3 or any(
|
|
56
|
+
part == "" for part in existing_result_name.split(".")
|
|
57
|
+
):
|
|
58
|
+
logger.warning(
|
|
59
|
+
f"_is_results_regex_match: existing_result_name illegal, will be ignored."
|
|
60
|
+
f" existing_result_name: {existing_result_name}"
|
|
61
|
+
)
|
|
62
|
+
return False
|
|
63
|
+
existing_result_name = ".".join(existing_result_name.split(".")[i] for i in [1, 3])
|
|
64
|
+
for result_name_filter in result_name_filters:
|
|
65
|
+
if fnmatchcase(existing_result_name, result_name_filter):
|
|
66
|
+
return True
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def filter_results_by_regex(
|
|
71
|
+
existing_result_names: Optional[list[str]] = None,
|
|
72
|
+
result_name_filters: Optional[list[str]] = None,
|
|
73
|
+
) -> list[str]:
|
|
74
|
+
"""
|
|
75
|
+
Filter a list of existing result names by a list of filters.
|
|
76
|
+
|
|
77
|
+
This function returns only the results that match the filters provided. If no filters are given,
|
|
78
|
+
it returns all results. Invalid inputs are ignored.
|
|
79
|
+
|
|
80
|
+
:param existing_result_names: List of existing results' fully qualified names (FQNs)
|
|
81
|
+
in the format: endpoint_id.app_name.type.name.
|
|
82
|
+
Example: mep1.app1.result.metric1
|
|
83
|
+
:param result_name_filters: List of filters in the format: app.result_name.
|
|
84
|
+
Wildcards can be used, such as app.result* or *.result
|
|
85
|
+
|
|
86
|
+
:return: List of FQNs of the matching results
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
if not result_name_filters:
|
|
90
|
+
return existing_result_names
|
|
91
|
+
|
|
92
|
+
if not existing_result_names:
|
|
93
|
+
return []
|
|
94
|
+
|
|
95
|
+
# filters validations
|
|
96
|
+
validated_filters = []
|
|
97
|
+
for result_name_filter in result_name_filters:
|
|
98
|
+
if result_name_filter.count(".") != 1:
|
|
99
|
+
logger.warning(
|
|
100
|
+
f"filter_results_by_regex: result_name_filter illegal, will be ignored."
|
|
101
|
+
f"Filter: {result_name_filter}"
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
validated_filters.append(result_name_filter)
|
|
105
|
+
filtered_metrics_names = []
|
|
106
|
+
for existing_result_name in existing_result_names:
|
|
107
|
+
if _is_results_regex_match(
|
|
108
|
+
existing_result_name=existing_result_name,
|
|
109
|
+
result_name_filters=validated_filters,
|
|
110
|
+
):
|
|
111
|
+
filtered_metrics_names.append(existing_result_name)
|
|
112
|
+
return filtered_metrics_names
|
|
113
|
+
|
|
114
|
+
|
|
48
115
|
def get_stream_path(
|
|
49
116
|
project: str,
|
|
50
117
|
function_name: str = mm_constants.MonitoringFunctionNames.STREAM,
|
|
@@ -162,24 +229,6 @@ def get_monitoring_drift_measures_data(project: str, endpoint_id: str) -> "DataI
|
|
|
162
229
|
)
|
|
163
230
|
|
|
164
231
|
|
|
165
|
-
def get_connection_string(
|
|
166
|
-
secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
|
|
167
|
-
) -> str:
|
|
168
|
-
"""Get endpoint store connection string from the project secret. If wasn't set, take it from the system
|
|
169
|
-
configurations.
|
|
170
|
-
|
|
171
|
-
:param secret_provider: An optional secret provider to get the connection string secret.
|
|
172
|
-
|
|
173
|
-
:return: Valid SQL connection string.
|
|
174
|
-
|
|
175
|
-
"""
|
|
176
|
-
|
|
177
|
-
return mlrun.get_secret_or_env(
|
|
178
|
-
key=mm_constants.ProjectSecretKeys.ENDPOINT_STORE_CONNECTION,
|
|
179
|
-
secret_provider=secret_provider,
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
|
|
183
232
|
def get_tsdb_connection_string(
|
|
184
233
|
secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
|
|
185
234
|
) -> str:
|
|
@@ -252,19 +301,24 @@ def update_model_endpoint_last_request(
|
|
|
252
301
|
:param current_request: current request time
|
|
253
302
|
:param db: DB interface.
|
|
254
303
|
"""
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
304
|
+
is_batch_endpoint = (
|
|
305
|
+
model_endpoint.metadata.endpoint_type == mm_constants.EndpointType.BATCH_EP
|
|
306
|
+
)
|
|
307
|
+
if not is_batch_endpoint:
|
|
258
308
|
logger.info(
|
|
259
309
|
"Update model endpoint last request time (EP with serving)",
|
|
260
310
|
project=project,
|
|
261
311
|
endpoint_id=model_endpoint.metadata.uid,
|
|
312
|
+
name=model_endpoint.metadata.name,
|
|
313
|
+
function_name=model_endpoint.spec.function_name,
|
|
262
314
|
last_request=model_endpoint.status.last_request,
|
|
263
315
|
current_request=current_request,
|
|
264
316
|
)
|
|
265
317
|
db.patch_model_endpoint(
|
|
266
318
|
project=project,
|
|
267
319
|
endpoint_id=model_endpoint.metadata.uid,
|
|
320
|
+
name=model_endpoint.metadata.name,
|
|
321
|
+
function_name=model_endpoint.spec.function_name,
|
|
268
322
|
attributes={mm_constants.EventFieldType.LAST_REQUEST: current_request},
|
|
269
323
|
)
|
|
270
324
|
else: # model endpoint without any serving function - close the window "manually"
|
|
@@ -283,7 +337,7 @@ def update_model_endpoint_last_request(
|
|
|
283
337
|
+ datetime.timedelta(
|
|
284
338
|
seconds=mlrun.mlconf.model_endpoint_monitoring.parquet_batching_timeout_secs
|
|
285
339
|
)
|
|
286
|
-
)
|
|
340
|
+
)
|
|
287
341
|
logger.info(
|
|
288
342
|
"Bumping model endpoint last request time (EP without serving)",
|
|
289
343
|
project=project,
|
|
@@ -295,6 +349,8 @@ def update_model_endpoint_last_request(
|
|
|
295
349
|
db.patch_model_endpoint(
|
|
296
350
|
project=project,
|
|
297
351
|
endpoint_id=model_endpoint.metadata.uid,
|
|
352
|
+
name=model_endpoint.metadata.name,
|
|
353
|
+
function_name=model_endpoint.spec.function_name,
|
|
298
354
|
attributes={mm_constants.EventFieldType.LAST_REQUEST: bumped_last_request},
|
|
299
355
|
)
|
|
300
356
|
|
|
@@ -336,17 +392,6 @@ def calculate_inputs_statistics(
|
|
|
336
392
|
return inputs_statistics
|
|
337
393
|
|
|
338
394
|
|
|
339
|
-
def get_endpoint_record(
|
|
340
|
-
project: str,
|
|
341
|
-
endpoint_id: str,
|
|
342
|
-
secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
|
|
343
|
-
) -> dict[str, typing.Any]:
|
|
344
|
-
model_endpoint_store = mlrun.model_monitoring.get_store_object(
|
|
345
|
-
project=project, secret_provider=secret_provider
|
|
346
|
-
)
|
|
347
|
-
return model_endpoint_store.get_model_endpoint(endpoint_id=endpoint_id)
|
|
348
|
-
|
|
349
|
-
|
|
350
395
|
def get_result_instance_fqn(
|
|
351
396
|
model_endpoint_id: str, app_name: str, result_name: str
|
|
352
397
|
) -> str:
|
|
@@ -386,38 +431,6 @@ def get_invocations_metric(project: str) -> ModelEndpointMonitoringMetric:
|
|
|
386
431
|
)
|
|
387
432
|
|
|
388
433
|
|
|
389
|
-
def enrich_model_endpoint_with_model_uri(
|
|
390
|
-
model_endpoint: ModelEndpoint,
|
|
391
|
-
model_obj: mlrun.artifacts.ModelArtifact,
|
|
392
|
-
):
|
|
393
|
-
"""
|
|
394
|
-
Enrich the model endpoint object with the model uri from the model object. We will use a unique reference
|
|
395
|
-
to the model object that includes the project, db_key, iter, and tree.
|
|
396
|
-
In addition, we verify that the model object is of type `ModelArtifact`.
|
|
397
|
-
|
|
398
|
-
:param model_endpoint: An object representing the model endpoint that will be enriched with the model uri.
|
|
399
|
-
:param model_obj: An object representing the model artifact.
|
|
400
|
-
|
|
401
|
-
:raise: `MLRunInvalidArgumentError` if the model object is not of type `ModelArtifact`.
|
|
402
|
-
"""
|
|
403
|
-
mlrun.utils.helpers.verify_field_of_type(
|
|
404
|
-
field_name="model_endpoint.spec.model_uri",
|
|
405
|
-
field_value=model_obj,
|
|
406
|
-
expected_type=mlrun.artifacts.ModelArtifact,
|
|
407
|
-
)
|
|
408
|
-
|
|
409
|
-
# Update model_uri with a unique reference to handle future changes
|
|
410
|
-
model_artifact_uri = mlrun.utils.helpers.generate_artifact_uri(
|
|
411
|
-
project=model_endpoint.metadata.project,
|
|
412
|
-
key=model_obj.db_key,
|
|
413
|
-
iter=model_obj.iter,
|
|
414
|
-
tree=model_obj.tree,
|
|
415
|
-
)
|
|
416
|
-
model_endpoint.spec.model_uri = mlrun.datastore.get_store_uri(
|
|
417
|
-
kind=mlrun.utils.helpers.StorePrefix.Model, uri=model_artifact_uri
|
|
418
|
-
)
|
|
419
|
-
|
|
420
|
-
|
|
421
434
|
def _get_monitoring_schedules_folder_path(project: str) -> str:
|
|
422
435
|
return typing.cast(
|
|
423
436
|
str,
|