mlrun 1.7.0rc5__py3-none-any.whl → 1.7.2__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 +39 -121
- mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
- mlrun/alerts/alert.py +248 -0
- mlrun/api/schemas/__init__.py +4 -3
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +39 -254
- mlrun/artifacts/dataset.py +9 -190
- mlrun/artifacts/manager.py +73 -46
- mlrun/artifacts/model.py +30 -158
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +73 -2
- mlrun/common/db/sql_session.py +3 -2
- mlrun/common/formatters/__init__.py +21 -0
- mlrun/common/formatters/artifact.py +46 -0
- mlrun/common/formatters/base.py +113 -0
- mlrun/common/formatters/feature_set.py +44 -0
- mlrun/common/formatters/function.py +46 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/common/formatters/run.py +29 -0
- mlrun/common/helpers.py +11 -1
- mlrun/{runtimes → common/runtimes}/constants.py +32 -4
- mlrun/common/schemas/__init__.py +21 -4
- mlrun/common/schemas/alert.py +202 -0
- mlrun/common/schemas/api_gateway.py +113 -2
- mlrun/common/schemas/artifact.py +28 -1
- mlrun/common/schemas/auth.py +11 -0
- mlrun/common/schemas/client_spec.py +2 -1
- mlrun/common/schemas/common.py +7 -4
- mlrun/common/schemas/constants.py +3 -0
- mlrun/common/schemas/feature_store.py +58 -28
- mlrun/common/schemas/frontend_spec.py +8 -0
- mlrun/common/schemas/function.py +11 -0
- mlrun/common/schemas/hub.py +7 -9
- mlrun/common/schemas/model_monitoring/__init__.py +21 -4
- mlrun/common/schemas/model_monitoring/constants.py +136 -42
- mlrun/common/schemas/model_monitoring/grafana.py +9 -5
- mlrun/common/schemas/model_monitoring/model_endpoints.py +89 -41
- mlrun/common/schemas/notification.py +69 -12
- mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
- mlrun/common/schemas/pipeline.py +7 -0
- mlrun/common/schemas/project.py +67 -16
- mlrun/common/schemas/runs.py +17 -0
- mlrun/common/schemas/schedule.py +1 -1
- mlrun/common/schemas/workflow.py +10 -2
- mlrun/common/types.py +14 -1
- mlrun/config.py +224 -58
- mlrun/data_types/data_types.py +11 -1
- mlrun/data_types/spark.py +5 -4
- mlrun/data_types/to_pandas.py +75 -34
- mlrun/datastore/__init__.py +8 -10
- mlrun/datastore/alibaba_oss.py +131 -0
- mlrun/datastore/azure_blob.py +131 -43
- mlrun/datastore/base.py +107 -47
- mlrun/datastore/datastore.py +17 -7
- mlrun/datastore/datastore_profile.py +91 -7
- mlrun/datastore/dbfs_store.py +3 -7
- mlrun/datastore/filestore.py +1 -3
- mlrun/datastore/google_cloud_storage.py +92 -32
- mlrun/datastore/hdfs.py +5 -0
- mlrun/datastore/inmem.py +6 -3
- mlrun/datastore/redis.py +3 -2
- mlrun/datastore/s3.py +30 -12
- mlrun/datastore/snowflake_utils.py +45 -0
- mlrun/datastore/sources.py +274 -59
- mlrun/datastore/spark_utils.py +30 -0
- mlrun/datastore/store_resources.py +9 -7
- mlrun/datastore/storeytargets.py +151 -0
- mlrun/datastore/targets.py +374 -102
- mlrun/datastore/utils.py +68 -5
- mlrun/datastore/v3io.py +28 -50
- mlrun/db/auth_utils.py +152 -0
- mlrun/db/base.py +231 -22
- mlrun/db/factory.py +1 -4
- mlrun/db/httpdb.py +864 -228
- mlrun/db/nopdb.py +268 -16
- mlrun/errors.py +35 -5
- mlrun/execution.py +111 -38
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +46 -53
- mlrun/feature_store/common.py +6 -11
- mlrun/feature_store/feature_set.py +48 -23
- mlrun/feature_store/feature_vector.py +13 -2
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +9 -4
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +13 -4
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +24 -32
- mlrun/feature_store/steps.py +38 -19
- mlrun/features.py +6 -14
- mlrun/frameworks/_common/plan.py +3 -3
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
- mlrun/frameworks/_ml_common/plan.py +1 -1
- 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 +4 -4
- mlrun/frameworks/pytorch/__init__.py +2 -2
- mlrun/frameworks/sklearn/__init__.py +1 -1
- mlrun/frameworks/sklearn/mlrun_interface.py +13 -3
- 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 +57 -12
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +6 -5
- mlrun/launcher/client.py +13 -11
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +15 -5
- mlrun/launcher/remote.py +10 -3
- mlrun/lists.py +6 -2
- mlrun/model.py +297 -48
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +152 -357
- mlrun/model_monitoring/applications/__init__.py +10 -0
- mlrun/model_monitoring/applications/_application_steps.py +190 -0
- mlrun/model_monitoring/applications/base.py +108 -0
- mlrun/model_monitoring/applications/context.py +341 -0
- mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
- mlrun/model_monitoring/applications/histogram_data_drift.py +227 -91
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +130 -303
- mlrun/model_monitoring/{stores/models/sqlite.py → db/__init__.py} +5 -10
- mlrun/model_monitoring/db/stores/__init__.py +136 -0
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/db/stores/base/store.py +213 -0
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -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 +659 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
- mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
- mlrun/model_monitoring/db/tsdb/base.py +448 -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 +298 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +522 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
- mlrun/model_monitoring/features_drift_table.py +34 -22
- mlrun/model_monitoring/helpers.py +177 -39
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +165 -398
- mlrun/model_monitoring/tracking_policy.py +7 -1
- mlrun/model_monitoring/writer.py +161 -125
- mlrun/package/packagers/default_packager.py +2 -2
- mlrun/package/packagers_manager.py +1 -0
- mlrun/package/utils/_formatter.py +2 -2
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +67 -228
- mlrun/projects/__init__.py +6 -1
- mlrun/projects/operations.py +47 -20
- mlrun/projects/pipelines.py +396 -249
- mlrun/projects/project.py +1125 -414
- mlrun/render.py +28 -22
- mlrun/run.py +207 -180
- mlrun/runtimes/__init__.py +76 -11
- mlrun/runtimes/base.py +40 -14
- mlrun/runtimes/daskjob.py +9 -2
- mlrun/runtimes/databricks_job/databricks_runtime.py +1 -0
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +1 -29
- mlrun/runtimes/kubejob.py +34 -128
- mlrun/runtimes/local.py +39 -10
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/abstract.py +8 -8
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/runtimes/nuclio/api_gateway.py +646 -177
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +758 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/nuclio/function.py +188 -68
- mlrun/runtimes/nuclio/serving.py +57 -60
- mlrun/runtimes/pod.py +191 -58
- mlrun/runtimes/remotesparkjob.py +11 -8
- mlrun/runtimes/sparkjob/spark3job.py +17 -18
- mlrun/runtimes/utils.py +40 -73
- mlrun/secrets.py +6 -2
- mlrun/serving/__init__.py +8 -1
- mlrun/serving/remote.py +2 -3
- mlrun/serving/routers.py +89 -64
- mlrun/serving/server.py +54 -26
- mlrun/serving/states.py +187 -56
- mlrun/serving/utils.py +19 -11
- mlrun/serving/v2_serving.py +136 -63
- mlrun/track/tracker.py +2 -1
- mlrun/track/trackers/mlflow_tracker.py +5 -0
- mlrun/utils/async_http.py +26 -6
- mlrun/utils/db.py +18 -0
- mlrun/utils/helpers.py +375 -105
- mlrun/utils/http.py +2 -2
- mlrun/utils/logger.py +75 -9
- mlrun/utils/notifications/notification/__init__.py +14 -10
- mlrun/utils/notifications/notification/base.py +48 -0
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +24 -1
- mlrun/utils/notifications/notification/ipython.py +2 -0
- mlrun/utils/notifications/notification/slack.py +96 -21
- mlrun/utils/notifications/notification/webhook.py +63 -2
- mlrun/utils/notifications/notification_pusher.py +146 -16
- mlrun/utils/regex.py +9 -0
- mlrun/utils/retryer.py +3 -2
- mlrun/utils/v3io_clients.py +2 -3
- mlrun/utils/version/version.json +2 -2
- mlrun-1.7.2.dist-info/METADATA +390 -0
- mlrun-1.7.2.dist-info/RECORD +351 -0
- {mlrun-1.7.0rc5.dist-info → mlrun-1.7.2.dist-info}/WHEEL +1 -1
- mlrun/feature_store/retrieval/conversion.py +0 -271
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/application.py +0 -310
- mlrun/model_monitoring/batch.py +0 -974
- mlrun/model_monitoring/controller_handler.py +0 -37
- mlrun/model_monitoring/prometheus.py +0 -216
- mlrun/model_monitoring/stores/__init__.py +0 -111
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -574
- mlrun/model_monitoring/stores/model_endpoint_store.py +0 -145
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/models/base.py +0 -84
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
- mlrun/platforms/other.py +0 -305
- mlrun-1.7.0rc5.dist-info/METADATA +0 -269
- mlrun-1.7.0rc5.dist-info/RECORD +0 -323
- {mlrun-1.7.0rc5.dist-info → mlrun-1.7.2.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc5.dist-info → mlrun-1.7.2.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc5.dist-info → mlrun-1.7.2.dist-info}/top_level.txt +0 -0
mlrun/execution.py
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
import logging
|
|
15
16
|
import os
|
|
16
17
|
import uuid
|
|
17
18
|
from copy import deepcopy
|
|
@@ -22,6 +23,8 @@ import yaml
|
|
|
22
23
|
from dateutil import parser
|
|
23
24
|
|
|
24
25
|
import mlrun
|
|
26
|
+
import mlrun.common.constants as mlrun_constants
|
|
27
|
+
import mlrun.common.formatters
|
|
25
28
|
from mlrun.artifacts import ModelArtifact
|
|
26
29
|
from mlrun.datastore.store_resources import get_store_resource
|
|
27
30
|
from mlrun.errors import MLRunInvalidArgumentError
|
|
@@ -33,13 +36,13 @@ from .features import Feature
|
|
|
33
36
|
from .model import HyperParamOptions
|
|
34
37
|
from .secrets import SecretsStore
|
|
35
38
|
from .utils import (
|
|
39
|
+
RunKeys,
|
|
36
40
|
dict_to_json,
|
|
37
41
|
dict_to_yaml,
|
|
38
42
|
get_in,
|
|
39
43
|
is_relative_path,
|
|
40
44
|
logger,
|
|
41
45
|
now_date,
|
|
42
|
-
run_keys,
|
|
43
46
|
to_date_str,
|
|
44
47
|
update_in,
|
|
45
48
|
)
|
|
@@ -77,13 +80,13 @@ class MLClientCtx:
|
|
|
77
80
|
self._tmpfile = tmp
|
|
78
81
|
self._logger = log_stream or logger
|
|
79
82
|
self._log_level = "info"
|
|
80
|
-
self._matrics_db = None
|
|
81
83
|
self._autocommit = autocommit
|
|
82
84
|
self._notifications = []
|
|
83
85
|
self._state_thresholds = {}
|
|
84
86
|
|
|
85
87
|
self._labels = {}
|
|
86
88
|
self._annotations = {}
|
|
89
|
+
self._node_selector = {}
|
|
87
90
|
|
|
88
91
|
self._function = ""
|
|
89
92
|
self._parameters = {}
|
|
@@ -101,8 +104,7 @@ class MLClientCtx:
|
|
|
101
104
|
self._error = None
|
|
102
105
|
self._commit = ""
|
|
103
106
|
self._host = None
|
|
104
|
-
self._start_time = now_date()
|
|
105
|
-
self._last_update = now_date()
|
|
107
|
+
self._start_time = self._last_update = now_date()
|
|
106
108
|
self._iteration_results = None
|
|
107
109
|
self._children = []
|
|
108
110
|
self._parent = None
|
|
@@ -110,6 +112,7 @@ class MLClientCtx:
|
|
|
110
112
|
|
|
111
113
|
self._project_object = None
|
|
112
114
|
self._allow_empty_resources = None
|
|
115
|
+
self._reset_on_run = None
|
|
113
116
|
|
|
114
117
|
def __enter__(self):
|
|
115
118
|
return self
|
|
@@ -129,7 +132,9 @@ class MLClientCtx:
|
|
|
129
132
|
@property
|
|
130
133
|
def tag(self):
|
|
131
134
|
"""Run tag (uid or workflow id if exists)"""
|
|
132
|
-
return
|
|
135
|
+
return (
|
|
136
|
+
self._labels.get(mlrun_constants.MLRunInternalLabels.workflow) or self._uid
|
|
137
|
+
)
|
|
133
138
|
|
|
134
139
|
@property
|
|
135
140
|
def state(self):
|
|
@@ -165,6 +170,8 @@ class MLClientCtx:
|
|
|
165
170
|
@log_level.setter
|
|
166
171
|
def log_level(self, value: str):
|
|
167
172
|
"""Set the logging level, e.g. 'debug', 'info', 'error'"""
|
|
173
|
+
level = logging.getLevelName(value.upper())
|
|
174
|
+
self._logger.set_logger_level(level)
|
|
168
175
|
self._log_level = value
|
|
169
176
|
|
|
170
177
|
@property
|
|
@@ -203,6 +210,11 @@ class MLClientCtx:
|
|
|
203
210
|
"""Dictionary with labels (read-only)"""
|
|
204
211
|
return deepcopy(self._labels)
|
|
205
212
|
|
|
213
|
+
@property
|
|
214
|
+
def node_selector(self):
|
|
215
|
+
"""Dictionary with node selectors (read-only)"""
|
|
216
|
+
return deepcopy(self._node_selector)
|
|
217
|
+
|
|
206
218
|
@property
|
|
207
219
|
def annotations(self):
|
|
208
220
|
"""Dictionary with annotations (read-only)"""
|
|
@@ -224,12 +236,12 @@ class MLClientCtx:
|
|
|
224
236
|
with context.get_child_context(myparam=param) as child:
|
|
225
237
|
accuracy = child_handler(child, df, **child.parameters)
|
|
226
238
|
accuracy_sum += accuracy
|
|
227
|
-
child.log_result(
|
|
239
|
+
child.log_result("accuracy", accuracy)
|
|
228
240
|
if accuracy > best_accuracy:
|
|
229
241
|
child.mark_as_best()
|
|
230
242
|
best_accuracy = accuracy
|
|
231
243
|
|
|
232
|
-
context.log_result(
|
|
244
|
+
context.log_result("avg_accuracy", accuracy_sum / len(param_list))
|
|
233
245
|
|
|
234
246
|
:param params: Extra (or override) params to parent context
|
|
235
247
|
:param with_parent_params: Child will copy the parent parameters and add to them
|
|
@@ -289,7 +301,9 @@ class MLClientCtx:
|
|
|
289
301
|
|
|
290
302
|
Example::
|
|
291
303
|
|
|
292
|
-
feature_vector = context.get_store_resource(
|
|
304
|
+
feature_vector = context.get_store_resource(
|
|
305
|
+
"store://feature-vectors/default/myvec"
|
|
306
|
+
)
|
|
293
307
|
dataset = context.get_store_resource("store://artifacts/default/mydata")
|
|
294
308
|
|
|
295
309
|
:param url: Store resource uri/path, store://<type>/<project>/<name>:<version>
|
|
@@ -325,10 +339,12 @@ class MLClientCtx:
|
|
|
325
339
|
"name": self.name,
|
|
326
340
|
"kind": "run",
|
|
327
341
|
"uri": uri,
|
|
328
|
-
"owner": get_in(self._labels,
|
|
342
|
+
"owner": get_in(self._labels, mlrun_constants.MLRunInternalLabels.owner),
|
|
329
343
|
}
|
|
330
|
-
if
|
|
331
|
-
resp[
|
|
344
|
+
if mlrun_constants.MLRunInternalLabels.workflow in self._labels:
|
|
345
|
+
resp[mlrun_constants.MLRunInternalLabels.workflow] = self._labels[
|
|
346
|
+
mlrun_constants.MLRunInternalLabels.workflow
|
|
347
|
+
]
|
|
332
348
|
return resp
|
|
333
349
|
|
|
334
350
|
@classmethod
|
|
@@ -357,7 +373,7 @@ class MLClientCtx:
|
|
|
357
373
|
self._labels = meta.get("labels", self._labels)
|
|
358
374
|
spec = attrs.get("spec")
|
|
359
375
|
if spec:
|
|
360
|
-
self._secrets_manager = SecretsStore.from_list(spec.get(
|
|
376
|
+
self._secrets_manager = SecretsStore.from_list(spec.get(RunKeys.secrets))
|
|
361
377
|
self._log_level = spec.get("log_level", self._log_level)
|
|
362
378
|
self._function = spec.get("function", self._function)
|
|
363
379
|
self._parameters = spec.get("parameters", self._parameters)
|
|
@@ -375,13 +391,15 @@ class MLClientCtx:
|
|
|
375
391
|
self._allow_empty_resources = spec.get(
|
|
376
392
|
"allow_empty_resources", self._allow_empty_resources
|
|
377
393
|
)
|
|
378
|
-
self.artifact_path = spec.get(
|
|
379
|
-
self._in_path = spec.get(
|
|
380
|
-
inputs = spec.get(
|
|
394
|
+
self.artifact_path = spec.get(RunKeys.output_path, self.artifact_path)
|
|
395
|
+
self._in_path = spec.get(RunKeys.input_path, self._in_path)
|
|
396
|
+
inputs = spec.get(RunKeys.inputs)
|
|
381
397
|
self._notifications = spec.get("notifications", self._notifications)
|
|
382
398
|
self._state_thresholds = spec.get(
|
|
383
399
|
"state_thresholds", self._state_thresholds
|
|
384
400
|
)
|
|
401
|
+
self._node_selector = spec.get("node_selector", self._node_selector)
|
|
402
|
+
self._reset_on_run = spec.get("reset_on_run", self._reset_on_run)
|
|
385
403
|
|
|
386
404
|
self._init_dbs(rundb)
|
|
387
405
|
|
|
@@ -394,7 +412,7 @@ class MLClientCtx:
|
|
|
394
412
|
self._set_input(k, v)
|
|
395
413
|
|
|
396
414
|
if host and not is_api:
|
|
397
|
-
self.set_label(
|
|
415
|
+
self.set_label(mlrun_constants.MLRunInternalLabels.host, host)
|
|
398
416
|
|
|
399
417
|
start = get_in(attrs, "status.start_time")
|
|
400
418
|
if start:
|
|
@@ -421,7 +439,7 @@ class MLClientCtx:
|
|
|
421
439
|
|
|
422
440
|
Example::
|
|
423
441
|
|
|
424
|
-
data_path=context.artifact_subpath(
|
|
442
|
+
data_path = context.artifact_subpath("data")
|
|
425
443
|
|
|
426
444
|
"""
|
|
427
445
|
return os.path.join(self.artifact_path, *subpaths)
|
|
@@ -525,7 +543,7 @@ class MLClientCtx:
|
|
|
525
543
|
|
|
526
544
|
Example::
|
|
527
545
|
|
|
528
|
-
context.log_result(
|
|
546
|
+
context.log_result("accuracy", 0.85)
|
|
529
547
|
|
|
530
548
|
:param key: Result key
|
|
531
549
|
:param value: Result value
|
|
@@ -539,7 +557,7 @@ class MLClientCtx:
|
|
|
539
557
|
|
|
540
558
|
Example::
|
|
541
559
|
|
|
542
|
-
context.log_results({
|
|
560
|
+
context.log_results({"accuracy": 0.85, "loss": 0.2})
|
|
543
561
|
|
|
544
562
|
:param results: Key/value dict or results
|
|
545
563
|
:param commit: Commit (write to DB now vs wait for the end of the run)
|
|
@@ -558,7 +576,7 @@ class MLClientCtx:
|
|
|
558
576
|
self._results["best_iteration"] = best
|
|
559
577
|
for k, v in get_in(task, ["status", "results"], {}).items():
|
|
560
578
|
self._results[k] = v
|
|
561
|
-
for artifact in get_in(task, ["status",
|
|
579
|
+
for artifact in get_in(task, ["status", RunKeys.artifacts], []):
|
|
562
580
|
self._artifacts_manager.artifacts[artifact["metadata"]["key"]] = (
|
|
563
581
|
artifact
|
|
564
582
|
)
|
|
@@ -617,7 +635,9 @@ class MLClientCtx:
|
|
|
617
635
|
:param viewer: Kubeflow viewer type
|
|
618
636
|
:param target_path: Absolute target path (instead of using artifact_path + local_path)
|
|
619
637
|
:param src_path: Deprecated, use local_path
|
|
620
|
-
:param upload:
|
|
638
|
+
:param upload: Whether to upload the artifact to the datastore. If not provided, and the `local_path`
|
|
639
|
+
is not a directory, upload occurs by default. Directories are uploaded only when this
|
|
640
|
+
flag is explicitly set to `True`.
|
|
621
641
|
:param labels: A set of key/value labels to tag the artifact with
|
|
622
642
|
:param format: Optional, format to use (e.g. csv, parquet, ..)
|
|
623
643
|
:param db_key: The key to use in the artifact DB table, by default its run name + '_' + key
|
|
@@ -674,7 +694,9 @@ class MLClientCtx:
|
|
|
674
694
|
"age": [42, 52, 36, 24, 73],
|
|
675
695
|
"testScore": [25, 94, 57, 62, 70],
|
|
676
696
|
}
|
|
677
|
-
df = pd.DataFrame(
|
|
697
|
+
df = pd.DataFrame(
|
|
698
|
+
raw_data, columns=["first_name", "last_name", "age", "testScore"]
|
|
699
|
+
)
|
|
678
700
|
context.log_dataset("mydf", df=df, stats=True)
|
|
679
701
|
|
|
680
702
|
:param key: Artifact key
|
|
@@ -752,13 +774,16 @@ class MLClientCtx:
|
|
|
752
774
|
|
|
753
775
|
Example::
|
|
754
776
|
|
|
755
|
-
context.log_model(
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
777
|
+
context.log_model(
|
|
778
|
+
"model",
|
|
779
|
+
body=dumps(model),
|
|
780
|
+
model_file="model.pkl",
|
|
781
|
+
metrics=context.results,
|
|
782
|
+
training_set=training_df,
|
|
783
|
+
label_column="label",
|
|
784
|
+
feature_vector=feature_vector_uri,
|
|
785
|
+
labels={"app": "fraud"},
|
|
786
|
+
)
|
|
762
787
|
|
|
763
788
|
:param key: Artifact key or artifact class ()
|
|
764
789
|
:param body: Will use the body as the artifact content
|
|
@@ -902,6 +927,43 @@ class MLClientCtx:
|
|
|
902
927
|
updates, self._uid, self.project, iter=self._iteration
|
|
903
928
|
)
|
|
904
929
|
|
|
930
|
+
def get_notifications(self, unmask_secret_params=False):
|
|
931
|
+
"""
|
|
932
|
+
Get the list of notifications
|
|
933
|
+
|
|
934
|
+
:param unmask_secret_params: Used as a workaround for sending notification from workflow-runner.
|
|
935
|
+
When used, if the notification will be saved again a new secret will be created.
|
|
936
|
+
"""
|
|
937
|
+
|
|
938
|
+
# Get the full notifications from the DB since the run context does not contain the params due to bloating
|
|
939
|
+
run = self._rundb.read_run(
|
|
940
|
+
self.uid, format_=mlrun.common.formatters.RunFormat.notifications
|
|
941
|
+
)
|
|
942
|
+
|
|
943
|
+
notifications = []
|
|
944
|
+
for notification in run["spec"]["notifications"]:
|
|
945
|
+
notification: mlrun.model.Notification = mlrun.model.Notification.from_dict(
|
|
946
|
+
notification
|
|
947
|
+
)
|
|
948
|
+
# Fill the secret params from the project secret. We cannot use the server side internal secret mechanism
|
|
949
|
+
# here as it is the client side.
|
|
950
|
+
# TODO: This is a workaround to allow the notification to get the secret params from project secret
|
|
951
|
+
# instead of getting them from the internal project secret that should be mounted.
|
|
952
|
+
# We should mount the internal project secret that was created to the workflow-runner
|
|
953
|
+
# and get the secret from there.
|
|
954
|
+
if unmask_secret_params:
|
|
955
|
+
try:
|
|
956
|
+
notification.enrich_unmasked_secret_params_from_project_secret()
|
|
957
|
+
notifications.append(notification)
|
|
958
|
+
except mlrun.errors.MLRunValueError:
|
|
959
|
+
logger.warning(
|
|
960
|
+
"Failed to fill secret params from project secret for notification."
|
|
961
|
+
"Skip this notification.",
|
|
962
|
+
notification=notification.name,
|
|
963
|
+
)
|
|
964
|
+
|
|
965
|
+
return notifications
|
|
966
|
+
|
|
905
967
|
def to_dict(self):
|
|
906
968
|
"""Convert the run context to a dictionary"""
|
|
907
969
|
|
|
@@ -925,10 +987,11 @@ class MLClientCtx:
|
|
|
925
987
|
"parameters": self._parameters,
|
|
926
988
|
"handler": self._handler,
|
|
927
989
|
"outputs": self._outputs,
|
|
928
|
-
|
|
929
|
-
|
|
990
|
+
RunKeys.output_path: self.artifact_path,
|
|
991
|
+
RunKeys.inputs: self._inputs,
|
|
930
992
|
"notifications": self._notifications,
|
|
931
993
|
"state_thresholds": self._state_thresholds,
|
|
994
|
+
"node_selector": self._node_selector,
|
|
932
995
|
},
|
|
933
996
|
"status": {
|
|
934
997
|
"results": self._results,
|
|
@@ -950,7 +1013,7 @@ class MLClientCtx:
|
|
|
950
1013
|
set_if_not_none(struct["status"], "commit", self._commit)
|
|
951
1014
|
set_if_not_none(struct["status"], "iterations", self._iteration_results)
|
|
952
1015
|
|
|
953
|
-
struct["status"][
|
|
1016
|
+
struct["status"][RunKeys.artifacts] = self._artifacts_manager.artifact_list()
|
|
954
1017
|
self._data_stores.to_dict(struct["spec"])
|
|
955
1018
|
return struct
|
|
956
1019
|
|
|
@@ -983,10 +1046,15 @@ class MLClientCtx:
|
|
|
983
1046
|
# If it's a OpenMPI job, get the global rank and compare to the logging rank (worker) set in MLRun's
|
|
984
1047
|
# configuration:
|
|
985
1048
|
labels = self.labels
|
|
986
|
-
if
|
|
1049
|
+
if (
|
|
1050
|
+
mlrun_constants.MLRunInternalLabels.host in labels
|
|
1051
|
+
and labels.get(mlrun_constants.MLRunInternalLabels.kind, "job") == "mpijob"
|
|
1052
|
+
):
|
|
987
1053
|
# The host (pod name) of each worker is created by k8s, and by default it uses the rank number as the id in
|
|
988
1054
|
# the following template: ...-worker-<rank>
|
|
989
|
-
rank = int(
|
|
1055
|
+
rank = int(
|
|
1056
|
+
labels[mlrun_constants.MLRunInternalLabels.host].rsplit("-", 1)[1]
|
|
1057
|
+
)
|
|
990
1058
|
return rank == mlrun.mlconf.packagers.logging_worker
|
|
991
1059
|
|
|
992
1060
|
# Single worker is always the logging worker:
|
|
@@ -1022,9 +1090,14 @@ class MLClientCtx:
|
|
|
1022
1090
|
"status.last_update": to_date_str(self._last_update),
|
|
1023
1091
|
}
|
|
1024
1092
|
|
|
1025
|
-
#
|
|
1026
|
-
# multiple executions for a single run (e.g. mpi)
|
|
1027
|
-
|
|
1093
|
+
# Completion of runs is decided by the API runs monitoring as there may be
|
|
1094
|
+
# multiple executions for a single run (e.g. mpi).
|
|
1095
|
+
# For kinds that are not monitored by the API (local) we allow changing the state.
|
|
1096
|
+
run_kind = self.labels.get(mlrun_constants.MLRunInternalLabels.kind, "")
|
|
1097
|
+
if (
|
|
1098
|
+
mlrun.runtimes.RuntimeKinds.is_local_runtime(run_kind)
|
|
1099
|
+
or self._state != "completed"
|
|
1100
|
+
):
|
|
1028
1101
|
struct["status.state"] = self._state
|
|
1029
1102
|
|
|
1030
1103
|
if self.is_logging_worker():
|
|
@@ -1034,7 +1107,7 @@ class MLClientCtx:
|
|
|
1034
1107
|
set_if_not_none(struct, "status.commit", self._commit)
|
|
1035
1108
|
set_if_not_none(struct, "status.iterations", self._iteration_results)
|
|
1036
1109
|
|
|
1037
|
-
struct[f"status.{
|
|
1110
|
+
struct[f"status.{RunKeys.artifacts}"] = self._artifacts_manager.artifact_list()
|
|
1038
1111
|
return struct
|
|
1039
1112
|
|
|
1040
1113
|
def _init_dbs(self, rundb):
|
mlrun/feature_store/__init__.py
CHANGED
|
@@ -19,7 +19,6 @@ __all__ = [
|
|
|
19
19
|
"get_online_feature_service",
|
|
20
20
|
"ingest",
|
|
21
21
|
"preview",
|
|
22
|
-
"deploy_ingestion_service",
|
|
23
22
|
"deploy_ingestion_service_v2",
|
|
24
23
|
"delete_feature_set",
|
|
25
24
|
"delete_feature_vector",
|
|
@@ -41,7 +40,6 @@ from ..features import Entity, Feature
|
|
|
41
40
|
from .api import (
|
|
42
41
|
delete_feature_set,
|
|
43
42
|
delete_feature_vector,
|
|
44
|
-
deploy_ingestion_service,
|
|
45
43
|
deploy_ingestion_service_v2,
|
|
46
44
|
get_feature_set,
|
|
47
45
|
get_feature_vector,
|
mlrun/feature_store/api.py
CHANGED
|
@@ -113,6 +113,7 @@ def get_offline_features(
|
|
|
113
113
|
order_by: Union[str, list[str]] = None,
|
|
114
114
|
spark_service: str = None,
|
|
115
115
|
timestamp_for_filtering: Union[str, dict[str, str]] = None,
|
|
116
|
+
additional_filters: list = None,
|
|
116
117
|
):
|
|
117
118
|
"""retrieve offline feature vector results
|
|
118
119
|
|
|
@@ -136,7 +137,10 @@ def get_offline_features(
|
|
|
136
137
|
]
|
|
137
138
|
vector = FeatureVector(features=features)
|
|
138
139
|
resp = get_offline_features(
|
|
139
|
-
vector,
|
|
140
|
+
vector,
|
|
141
|
+
entity_rows=trades,
|
|
142
|
+
entity_timestamp_column="time",
|
|
143
|
+
query="ticker in ['GOOG'] and bid>100",
|
|
140
144
|
)
|
|
141
145
|
print(resp.to_dataframe())
|
|
142
146
|
print(vector.get_stats_table())
|
|
@@ -172,6 +176,13 @@ def get_offline_features(
|
|
|
172
176
|
By default, the filter executes on the timestamp_key of each feature set.
|
|
173
177
|
Note: the time filtering is performed on each feature set before the
|
|
174
178
|
merge process using start_time and end_time params.
|
|
179
|
+
:param additional_filters: List of additional_filter conditions as tuples.
|
|
180
|
+
Each tuple should be in the format (column_name, operator, value).
|
|
181
|
+
Supported operators: "=", ">=", "<=", ">", "<".
|
|
182
|
+
Example: [("Product", "=", "Computer")]
|
|
183
|
+
For all supported filters, please see:
|
|
184
|
+
https://arrow.apache.org/docs/python/generated/pyarrow.parquet.ParquetDataset.html
|
|
185
|
+
|
|
175
186
|
|
|
176
187
|
"""
|
|
177
188
|
return _get_offline_features(
|
|
@@ -191,6 +202,7 @@ def get_offline_features(
|
|
|
191
202
|
order_by,
|
|
192
203
|
spark_service,
|
|
193
204
|
timestamp_for_filtering,
|
|
205
|
+
additional_filters,
|
|
194
206
|
)
|
|
195
207
|
|
|
196
208
|
|
|
@@ -211,12 +223,18 @@ def _get_offline_features(
|
|
|
211
223
|
order_by: Union[str, list[str]] = None,
|
|
212
224
|
spark_service: str = None,
|
|
213
225
|
timestamp_for_filtering: Union[str, dict[str, str]] = None,
|
|
226
|
+
additional_filters=None,
|
|
214
227
|
) -> Union[OfflineVectorResponse, RemoteVectorResponse]:
|
|
215
228
|
if entity_rows is None and entity_timestamp_column is not None:
|
|
216
229
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
217
230
|
"entity_timestamp_column param "
|
|
218
231
|
"can not be specified without entity_rows param"
|
|
219
232
|
)
|
|
233
|
+
if isinstance(target, BaseStoreTarget) and not target.support_pandas:
|
|
234
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
235
|
+
f"get_offline_features does not support targets that do not support pandas engine."
|
|
236
|
+
f" Target kind: {target.kind}"
|
|
237
|
+
)
|
|
220
238
|
|
|
221
239
|
if isinstance(feature_vector, FeatureVector):
|
|
222
240
|
update_stats = True
|
|
@@ -249,6 +267,7 @@ def _get_offline_features(
|
|
|
249
267
|
start_time=start_time,
|
|
250
268
|
end_time=end_time,
|
|
251
269
|
timestamp_for_filtering=timestamp_for_filtering,
|
|
270
|
+
additional_filters=additional_filters,
|
|
252
271
|
)
|
|
253
272
|
|
|
254
273
|
merger = merger_engine(feature_vector, **(engine_args or {}))
|
|
@@ -264,6 +283,7 @@ def _get_offline_features(
|
|
|
264
283
|
update_stats=update_stats,
|
|
265
284
|
query=query,
|
|
266
285
|
order_by=order_by,
|
|
286
|
+
additional_filters=additional_filters,
|
|
267
287
|
)
|
|
268
288
|
|
|
269
289
|
|
|
@@ -307,7 +327,7 @@ def get_online_feature_service(
|
|
|
307
327
|
|
|
308
328
|
Example::
|
|
309
329
|
|
|
310
|
-
svc = get_online_feature_service(vector_uri, entity_keys=[
|
|
330
|
+
svc = get_online_feature_service(vector_uri, entity_keys=["ticker"])
|
|
311
331
|
try:
|
|
312
332
|
resp = svc.get([{"ticker": "GOOG"}, {"ticker": "MSFT"}])
|
|
313
333
|
print(resp)
|
|
@@ -456,7 +476,7 @@ def ingest(
|
|
|
456
476
|
df = ingest(stocks_set, stocks, infer_options=fstore.InferOptions.default())
|
|
457
477
|
|
|
458
478
|
# for running as remote job
|
|
459
|
-
config = RunConfig(image=
|
|
479
|
+
config = RunConfig(image="mlrun/mlrun")
|
|
460
480
|
df = ingest(stocks_set, stocks, run_config=config)
|
|
461
481
|
|
|
462
482
|
# specify source and targets
|
|
@@ -1002,53 +1022,6 @@ def _deploy_ingestion_service_v2(
|
|
|
1002
1022
|
return function.deploy(), function
|
|
1003
1023
|
|
|
1004
1024
|
|
|
1005
|
-
@deprecated(
|
|
1006
|
-
version="1.5.0",
|
|
1007
|
-
reason="'deploy_ingestion_service' will be removed in 1.7.0, use 'deploy_ingestion_service_v2' instead",
|
|
1008
|
-
category=FutureWarning,
|
|
1009
|
-
)
|
|
1010
|
-
def deploy_ingestion_service(
|
|
1011
|
-
featureset: Union[FeatureSet, str],
|
|
1012
|
-
source: DataSource = None,
|
|
1013
|
-
targets: list[DataTargetBase] = None,
|
|
1014
|
-
name: str = None,
|
|
1015
|
-
run_config: RunConfig = None,
|
|
1016
|
-
verbose=False,
|
|
1017
|
-
) -> str:
|
|
1018
|
-
"""Start real-time ingestion service using nuclio function
|
|
1019
|
-
|
|
1020
|
-
Deploy a real-time function implementing feature ingestion pipeline
|
|
1021
|
-
the source maps to Nuclio event triggers (http, kafka, v3io stream, etc.)
|
|
1022
|
-
|
|
1023
|
-
the `run_config` parameter allow specifying the function and job configuration,
|
|
1024
|
-
see: :py:class:`~mlrun.feature_store.RunConfig`
|
|
1025
|
-
|
|
1026
|
-
example::
|
|
1027
|
-
|
|
1028
|
-
source = HTTPSource()
|
|
1029
|
-
func = mlrun.code_to_function("ingest", kind="serving").apply(mount_v3io())
|
|
1030
|
-
config = RunConfig(function=func)
|
|
1031
|
-
my_set.deploy_ingestion_service(source, run_config=config)
|
|
1032
|
-
|
|
1033
|
-
:param featureset: feature set object or uri
|
|
1034
|
-
:param source: data source object describing the online or offline source
|
|
1035
|
-
:param targets: list of data target objects
|
|
1036
|
-
:param name: name for the job/function
|
|
1037
|
-
:param run_config: service runtime configuration (function object/uri, resources, etc..)
|
|
1038
|
-
:param verbose: verbose log
|
|
1039
|
-
|
|
1040
|
-
:return: URL to access the deployed ingestion service
|
|
1041
|
-
"""
|
|
1042
|
-
endpoint, _ = featureset.deploy_ingestion_service(
|
|
1043
|
-
source=source,
|
|
1044
|
-
targets=targets,
|
|
1045
|
-
name=name,
|
|
1046
|
-
run_config=run_config,
|
|
1047
|
-
verbose=verbose,
|
|
1048
|
-
)
|
|
1049
|
-
return endpoint
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
1025
|
def _ingest_with_spark(
|
|
1053
1026
|
spark=None,
|
|
1054
1027
|
featureset: Union[FeatureSet, str] = None,
|
|
@@ -1064,6 +1037,8 @@ def _ingest_with_spark(
|
|
|
1064
1037
|
try:
|
|
1065
1038
|
import pyspark.sql
|
|
1066
1039
|
|
|
1040
|
+
from mlrun.datastore.spark_utils import check_special_columns_exists
|
|
1041
|
+
|
|
1067
1042
|
if spark is None or spark is True:
|
|
1068
1043
|
# create spark context
|
|
1069
1044
|
|
|
@@ -1076,13 +1051,13 @@ def _ingest_with_spark(
|
|
|
1076
1051
|
|
|
1077
1052
|
spark = (
|
|
1078
1053
|
pyspark.sql.SparkSession.builder.appName(session_name)
|
|
1054
|
+
.config("spark.driver.memory", "2g")
|
|
1079
1055
|
.config("spark.sql.session.timeZone", "UTC")
|
|
1080
1056
|
.getOrCreate()
|
|
1081
1057
|
)
|
|
1082
1058
|
created_spark_context = True
|
|
1083
1059
|
|
|
1084
1060
|
timestamp_key = featureset.spec.timestamp_key
|
|
1085
|
-
|
|
1086
1061
|
if isinstance(source, pd.DataFrame):
|
|
1087
1062
|
df = spark.createDataFrame(source)
|
|
1088
1063
|
elif isinstance(source, pyspark.sql.DataFrame):
|
|
@@ -1112,6 +1087,12 @@ def _ingest_with_spark(
|
|
|
1112
1087
|
target = get_target_driver(target, featureset)
|
|
1113
1088
|
target.set_resource(featureset)
|
|
1114
1089
|
if featureset.spec.passthrough and target.is_offline:
|
|
1090
|
+
check_special_columns_exists(
|
|
1091
|
+
spark_df=df,
|
|
1092
|
+
entities=featureset.spec.entities,
|
|
1093
|
+
timestamp_key=timestamp_key,
|
|
1094
|
+
label_column=featureset.spec.label_column,
|
|
1095
|
+
)
|
|
1115
1096
|
continue
|
|
1116
1097
|
spark_options = target.get_spark_options(
|
|
1117
1098
|
key_columns, timestamp_key, overwrite
|
|
@@ -1121,9 +1102,21 @@ def _ingest_with_spark(
|
|
|
1121
1102
|
df_to_write = target.prepare_spark_df(
|
|
1122
1103
|
df_to_write, key_columns, timestamp_key, spark_options
|
|
1123
1104
|
)
|
|
1105
|
+
write_format = spark_options.pop("format", None)
|
|
1106
|
+
# We can get to this point if the column exists in different letter cases,
|
|
1107
|
+
# so PySpark will be able to read it, but we still have to raise an exception for it.
|
|
1108
|
+
|
|
1109
|
+
# This check is here and not in to_spark_df because in spark_merger we can have a target
|
|
1110
|
+
# that has different letter cases than the source, like in SnowflakeTarget.
|
|
1111
|
+
check_special_columns_exists(
|
|
1112
|
+
spark_df=df_to_write,
|
|
1113
|
+
entities=featureset.spec.entities,
|
|
1114
|
+
timestamp_key=timestamp_key,
|
|
1115
|
+
label_column=featureset.spec.label_column,
|
|
1116
|
+
)
|
|
1124
1117
|
if overwrite:
|
|
1125
1118
|
write_spark_dataframe_with_options(
|
|
1126
|
-
spark_options, df_to_write, "overwrite"
|
|
1119
|
+
spark_options, df_to_write, "overwrite", write_format=write_format
|
|
1127
1120
|
)
|
|
1128
1121
|
else:
|
|
1129
1122
|
# appending an empty dataframe may cause an empty file to be created (e.g. when writing to parquet)
|
|
@@ -1131,7 +1124,7 @@ def _ingest_with_spark(
|
|
|
1131
1124
|
df_to_write.persist()
|
|
1132
1125
|
if df_to_write.count() > 0:
|
|
1133
1126
|
write_spark_dataframe_with_options(
|
|
1134
|
-
spark_options, df_to_write, "append"
|
|
1127
|
+
spark_options, df_to_write, "append", write_format=write_format
|
|
1135
1128
|
)
|
|
1136
1129
|
target.update_resource_status("ready")
|
|
1137
1130
|
|
mlrun/feature_store/common.py
CHANGED
|
@@ -37,17 +37,12 @@ def parse_feature_string(feature):
|
|
|
37
37
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
38
38
|
f"feature {feature} must be {expected_message}"
|
|
39
39
|
)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
feature_set
|
|
46
|
-
feature_name = splitted[1]
|
|
47
|
-
splitted = feature_name.split(" as ")
|
|
48
|
-
if len(splitted) > 1:
|
|
49
|
-
return feature_set.strip(), splitted[0].strip(), splitted[1].strip()
|
|
50
|
-
return feature_set.strip(), feature_name.strip(), None
|
|
40
|
+
feature_set, feature_name = feature.rsplit(feature_separator, 1)
|
|
41
|
+
feature_set = feature_set.strip()
|
|
42
|
+
split_result = feature_name.split(" as ", 1)
|
|
43
|
+
feature_name = split_result[0].strip()
|
|
44
|
+
alias = split_result[1].strip() if len(split_result) > 1 else None
|
|
45
|
+
return feature_set, feature_name, alias
|
|
51
46
|
|
|
52
47
|
|
|
53
48
|
def parse_project_name_from_feature_string(feature):
|