mlrun 1.6.4rc7__py3-none-any.whl → 1.7.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.

Files changed (305) hide show
  1. mlrun/__init__.py +11 -1
  2. mlrun/__main__.py +40 -122
  3. mlrun/alerts/__init__.py +15 -0
  4. mlrun/alerts/alert.py +248 -0
  5. mlrun/api/schemas/__init__.py +5 -4
  6. mlrun/artifacts/__init__.py +8 -3
  7. mlrun/artifacts/base.py +47 -257
  8. mlrun/artifacts/dataset.py +11 -192
  9. mlrun/artifacts/manager.py +79 -47
  10. mlrun/artifacts/model.py +31 -159
  11. mlrun/artifacts/plots.py +23 -380
  12. mlrun/common/constants.py +74 -1
  13. mlrun/common/db/sql_session.py +5 -5
  14. mlrun/common/formatters/__init__.py +21 -0
  15. mlrun/common/formatters/artifact.py +45 -0
  16. mlrun/common/formatters/base.py +113 -0
  17. mlrun/common/formatters/feature_set.py +33 -0
  18. mlrun/common/formatters/function.py +46 -0
  19. mlrun/common/formatters/pipeline.py +53 -0
  20. mlrun/common/formatters/project.py +51 -0
  21. mlrun/common/formatters/run.py +29 -0
  22. mlrun/common/helpers.py +12 -3
  23. mlrun/common/model_monitoring/helpers.py +9 -5
  24. mlrun/{runtimes → common/runtimes}/constants.py +37 -9
  25. mlrun/common/schemas/__init__.py +31 -5
  26. mlrun/common/schemas/alert.py +202 -0
  27. mlrun/common/schemas/api_gateway.py +196 -0
  28. mlrun/common/schemas/artifact.py +25 -4
  29. mlrun/common/schemas/auth.py +16 -5
  30. mlrun/common/schemas/background_task.py +1 -1
  31. mlrun/common/schemas/client_spec.py +4 -2
  32. mlrun/common/schemas/common.py +7 -4
  33. mlrun/common/schemas/constants.py +3 -0
  34. mlrun/common/schemas/feature_store.py +74 -44
  35. mlrun/common/schemas/frontend_spec.py +15 -7
  36. mlrun/common/schemas/function.py +12 -1
  37. mlrun/common/schemas/hub.py +11 -18
  38. mlrun/common/schemas/memory_reports.py +2 -2
  39. mlrun/common/schemas/model_monitoring/__init__.py +20 -4
  40. mlrun/common/schemas/model_monitoring/constants.py +123 -42
  41. mlrun/common/schemas/model_monitoring/grafana.py +13 -9
  42. mlrun/common/schemas/model_monitoring/model_endpoints.py +101 -54
  43. mlrun/common/schemas/notification.py +71 -14
  44. mlrun/common/schemas/object.py +2 -2
  45. mlrun/{model_monitoring/controller_handler.py → common/schemas/pagination.py} +9 -12
  46. mlrun/common/schemas/pipeline.py +8 -1
  47. mlrun/common/schemas/project.py +69 -18
  48. mlrun/common/schemas/runs.py +7 -1
  49. mlrun/common/schemas/runtime_resource.py +8 -12
  50. mlrun/common/schemas/schedule.py +4 -4
  51. mlrun/common/schemas/tag.py +1 -2
  52. mlrun/common/schemas/workflow.py +12 -4
  53. mlrun/common/types.py +14 -1
  54. mlrun/config.py +154 -69
  55. mlrun/data_types/data_types.py +6 -1
  56. mlrun/data_types/spark.py +2 -2
  57. mlrun/data_types/to_pandas.py +67 -37
  58. mlrun/datastore/__init__.py +6 -8
  59. mlrun/datastore/alibaba_oss.py +131 -0
  60. mlrun/datastore/azure_blob.py +143 -42
  61. mlrun/datastore/base.py +102 -58
  62. mlrun/datastore/datastore.py +34 -13
  63. mlrun/datastore/datastore_profile.py +146 -20
  64. mlrun/datastore/dbfs_store.py +3 -7
  65. mlrun/datastore/filestore.py +1 -4
  66. mlrun/datastore/google_cloud_storage.py +97 -33
  67. mlrun/datastore/hdfs.py +56 -0
  68. mlrun/datastore/inmem.py +6 -3
  69. mlrun/datastore/redis.py +7 -2
  70. mlrun/datastore/s3.py +34 -12
  71. mlrun/datastore/snowflake_utils.py +45 -0
  72. mlrun/datastore/sources.py +303 -111
  73. mlrun/datastore/spark_utils.py +31 -2
  74. mlrun/datastore/store_resources.py +9 -7
  75. mlrun/datastore/storeytargets.py +151 -0
  76. mlrun/datastore/targets.py +453 -176
  77. mlrun/datastore/utils.py +72 -58
  78. mlrun/datastore/v3io.py +6 -1
  79. mlrun/db/base.py +274 -41
  80. mlrun/db/factory.py +1 -1
  81. mlrun/db/httpdb.py +893 -225
  82. mlrun/db/nopdb.py +291 -33
  83. mlrun/errors.py +36 -6
  84. mlrun/execution.py +115 -42
  85. mlrun/feature_store/__init__.py +0 -2
  86. mlrun/feature_store/api.py +65 -73
  87. mlrun/feature_store/common.py +7 -12
  88. mlrun/feature_store/feature_set.py +76 -55
  89. mlrun/feature_store/feature_vector.py +39 -31
  90. mlrun/feature_store/ingestion.py +7 -6
  91. mlrun/feature_store/retrieval/base.py +16 -11
  92. mlrun/feature_store/retrieval/dask_merger.py +2 -0
  93. mlrun/feature_store/retrieval/job.py +13 -4
  94. mlrun/feature_store/retrieval/local_merger.py +2 -0
  95. mlrun/feature_store/retrieval/spark_merger.py +24 -32
  96. mlrun/feature_store/steps.py +45 -34
  97. mlrun/features.py +11 -21
  98. mlrun/frameworks/_common/artifacts_library.py +9 -9
  99. mlrun/frameworks/_common/mlrun_interface.py +5 -5
  100. mlrun/frameworks/_common/model_handler.py +48 -48
  101. mlrun/frameworks/_common/plan.py +5 -6
  102. mlrun/frameworks/_common/producer.py +3 -4
  103. mlrun/frameworks/_common/utils.py +5 -5
  104. mlrun/frameworks/_dl_common/loggers/logger.py +6 -7
  105. mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +9 -9
  106. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +23 -47
  107. mlrun/frameworks/_ml_common/artifacts_library.py +1 -2
  108. mlrun/frameworks/_ml_common/loggers/logger.py +3 -4
  109. mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +4 -5
  110. mlrun/frameworks/_ml_common/model_handler.py +24 -24
  111. mlrun/frameworks/_ml_common/pkl_model_server.py +2 -2
  112. mlrun/frameworks/_ml_common/plan.py +2 -2
  113. mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +2 -3
  114. mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +2 -3
  115. mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
  116. mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +3 -3
  117. mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
  118. mlrun/frameworks/_ml_common/utils.py +4 -4
  119. mlrun/frameworks/auto_mlrun/auto_mlrun.py +9 -9
  120. mlrun/frameworks/huggingface/model_server.py +4 -4
  121. mlrun/frameworks/lgbm/__init__.py +33 -33
  122. mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
  123. mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -5
  124. mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -5
  125. mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -3
  126. mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +6 -6
  127. mlrun/frameworks/lgbm/model_handler.py +10 -10
  128. mlrun/frameworks/lgbm/model_server.py +6 -6
  129. mlrun/frameworks/lgbm/utils.py +5 -5
  130. mlrun/frameworks/onnx/dataset.py +8 -8
  131. mlrun/frameworks/onnx/mlrun_interface.py +3 -3
  132. mlrun/frameworks/onnx/model_handler.py +6 -6
  133. mlrun/frameworks/onnx/model_server.py +7 -7
  134. mlrun/frameworks/parallel_coordinates.py +6 -6
  135. mlrun/frameworks/pytorch/__init__.py +18 -18
  136. mlrun/frameworks/pytorch/callbacks/callback.py +4 -5
  137. mlrun/frameworks/pytorch/callbacks/logging_callback.py +17 -17
  138. mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +11 -11
  139. mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +23 -29
  140. mlrun/frameworks/pytorch/callbacks_handler.py +38 -38
  141. mlrun/frameworks/pytorch/mlrun_interface.py +20 -20
  142. mlrun/frameworks/pytorch/model_handler.py +17 -17
  143. mlrun/frameworks/pytorch/model_server.py +7 -7
  144. mlrun/frameworks/sklearn/__init__.py +13 -13
  145. mlrun/frameworks/sklearn/estimator.py +4 -4
  146. mlrun/frameworks/sklearn/metrics_library.py +14 -14
  147. mlrun/frameworks/sklearn/mlrun_interface.py +16 -9
  148. mlrun/frameworks/sklearn/model_handler.py +2 -2
  149. mlrun/frameworks/tf_keras/__init__.py +10 -7
  150. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +15 -15
  151. mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +11 -11
  152. mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +19 -23
  153. mlrun/frameworks/tf_keras/mlrun_interface.py +9 -11
  154. mlrun/frameworks/tf_keras/model_handler.py +14 -14
  155. mlrun/frameworks/tf_keras/model_server.py +6 -6
  156. mlrun/frameworks/xgboost/__init__.py +13 -13
  157. mlrun/frameworks/xgboost/model_handler.py +6 -6
  158. mlrun/k8s_utils.py +61 -17
  159. mlrun/launcher/__init__.py +1 -1
  160. mlrun/launcher/base.py +16 -15
  161. mlrun/launcher/client.py +13 -11
  162. mlrun/launcher/factory.py +1 -1
  163. mlrun/launcher/local.py +23 -13
  164. mlrun/launcher/remote.py +17 -10
  165. mlrun/lists.py +7 -6
  166. mlrun/model.py +478 -103
  167. mlrun/model_monitoring/__init__.py +1 -1
  168. mlrun/model_monitoring/api.py +163 -371
  169. mlrun/{runtimes/mpijob/v1alpha1.py → model_monitoring/applications/__init__.py} +9 -15
  170. mlrun/model_monitoring/applications/_application_steps.py +188 -0
  171. mlrun/model_monitoring/applications/base.py +108 -0
  172. mlrun/model_monitoring/applications/context.py +341 -0
  173. mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
  174. mlrun/model_monitoring/applications/histogram_data_drift.py +354 -0
  175. mlrun/model_monitoring/applications/results.py +99 -0
  176. mlrun/model_monitoring/controller.py +131 -278
  177. mlrun/model_monitoring/db/__init__.py +18 -0
  178. mlrun/model_monitoring/db/stores/__init__.py +136 -0
  179. mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
  180. mlrun/model_monitoring/db/stores/base/store.py +213 -0
  181. mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
  182. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
  183. mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
  184. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -0
  185. mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
  186. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +659 -0
  187. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
  188. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
  189. mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
  190. mlrun/model_monitoring/db/tsdb/base.py +448 -0
  191. mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
  192. mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
  193. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +279 -0
  194. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
  195. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +507 -0
  196. mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
  197. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
  198. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
  199. mlrun/model_monitoring/features_drift_table.py +134 -106
  200. mlrun/model_monitoring/helpers.py +199 -55
  201. mlrun/model_monitoring/metrics/__init__.py +13 -0
  202. mlrun/model_monitoring/metrics/histogram_distance.py +127 -0
  203. mlrun/model_monitoring/model_endpoint.py +3 -2
  204. mlrun/model_monitoring/stream_processing.py +131 -398
  205. mlrun/model_monitoring/tracking_policy.py +9 -2
  206. mlrun/model_monitoring/writer.py +161 -125
  207. mlrun/package/__init__.py +6 -6
  208. mlrun/package/context_handler.py +5 -5
  209. mlrun/package/packager.py +7 -7
  210. mlrun/package/packagers/default_packager.py +8 -8
  211. mlrun/package/packagers/numpy_packagers.py +15 -15
  212. mlrun/package/packagers/pandas_packagers.py +5 -5
  213. mlrun/package/packagers/python_standard_library_packagers.py +10 -10
  214. mlrun/package/packagers_manager.py +19 -23
  215. mlrun/package/utils/_formatter.py +6 -6
  216. mlrun/package/utils/_pickler.py +2 -2
  217. mlrun/package/utils/_supported_format.py +4 -4
  218. mlrun/package/utils/log_hint_utils.py +2 -2
  219. mlrun/package/utils/type_hint_utils.py +4 -9
  220. mlrun/platforms/__init__.py +11 -10
  221. mlrun/platforms/iguazio.py +24 -203
  222. mlrun/projects/operations.py +52 -25
  223. mlrun/projects/pipelines.py +191 -197
  224. mlrun/projects/project.py +1227 -400
  225. mlrun/render.py +16 -19
  226. mlrun/run.py +209 -184
  227. mlrun/runtimes/__init__.py +83 -15
  228. mlrun/runtimes/base.py +51 -35
  229. mlrun/runtimes/daskjob.py +17 -10
  230. mlrun/runtimes/databricks_job/databricks_cancel_task.py +1 -1
  231. mlrun/runtimes/databricks_job/databricks_runtime.py +8 -7
  232. mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
  233. mlrun/runtimes/funcdoc.py +1 -29
  234. mlrun/runtimes/function_reference.py +1 -1
  235. mlrun/runtimes/kubejob.py +34 -128
  236. mlrun/runtimes/local.py +40 -11
  237. mlrun/runtimes/mpijob/__init__.py +0 -20
  238. mlrun/runtimes/mpijob/abstract.py +9 -10
  239. mlrun/runtimes/mpijob/v1.py +1 -1
  240. mlrun/{model_monitoring/stores/models/sqlite.py → runtimes/nuclio/__init__.py} +7 -9
  241. mlrun/runtimes/nuclio/api_gateway.py +769 -0
  242. mlrun/runtimes/nuclio/application/__init__.py +15 -0
  243. mlrun/runtimes/nuclio/application/application.py +758 -0
  244. mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
  245. mlrun/runtimes/{function.py → nuclio/function.py} +200 -83
  246. mlrun/runtimes/{nuclio.py → nuclio/nuclio.py} +6 -6
  247. mlrun/runtimes/{serving.py → nuclio/serving.py} +65 -68
  248. mlrun/runtimes/pod.py +281 -101
  249. mlrun/runtimes/remotesparkjob.py +12 -9
  250. mlrun/runtimes/sparkjob/spark3job.py +67 -51
  251. mlrun/runtimes/utils.py +41 -75
  252. mlrun/secrets.py +9 -5
  253. mlrun/serving/__init__.py +8 -1
  254. mlrun/serving/remote.py +2 -7
  255. mlrun/serving/routers.py +85 -69
  256. mlrun/serving/server.py +69 -44
  257. mlrun/serving/states.py +209 -36
  258. mlrun/serving/utils.py +22 -14
  259. mlrun/serving/v1_serving.py +6 -7
  260. mlrun/serving/v2_serving.py +129 -54
  261. mlrun/track/tracker.py +2 -1
  262. mlrun/track/tracker_manager.py +3 -3
  263. mlrun/track/trackers/mlflow_tracker.py +6 -2
  264. mlrun/utils/async_http.py +6 -8
  265. mlrun/utils/azure_vault.py +1 -1
  266. mlrun/utils/clones.py +1 -2
  267. mlrun/utils/condition_evaluator.py +3 -3
  268. mlrun/utils/db.py +21 -3
  269. mlrun/utils/helpers.py +405 -225
  270. mlrun/utils/http.py +3 -6
  271. mlrun/utils/logger.py +112 -16
  272. mlrun/utils/notifications/notification/__init__.py +17 -13
  273. mlrun/utils/notifications/notification/base.py +50 -2
  274. mlrun/utils/notifications/notification/console.py +2 -0
  275. mlrun/utils/notifications/notification/git.py +24 -1
  276. mlrun/utils/notifications/notification/ipython.py +3 -1
  277. mlrun/utils/notifications/notification/slack.py +96 -21
  278. mlrun/utils/notifications/notification/webhook.py +59 -2
  279. mlrun/utils/notifications/notification_pusher.py +149 -30
  280. mlrun/utils/regex.py +9 -0
  281. mlrun/utils/retryer.py +208 -0
  282. mlrun/utils/singleton.py +1 -1
  283. mlrun/utils/v3io_clients.py +4 -6
  284. mlrun/utils/version/version.json +2 -2
  285. mlrun/utils/version/version.py +2 -6
  286. mlrun-1.7.0.dist-info/METADATA +378 -0
  287. mlrun-1.7.0.dist-info/RECORD +351 -0
  288. {mlrun-1.6.4rc7.dist-info → mlrun-1.7.0.dist-info}/WHEEL +1 -1
  289. mlrun/feature_store/retrieval/conversion.py +0 -273
  290. mlrun/kfpops.py +0 -868
  291. mlrun/model_monitoring/application.py +0 -310
  292. mlrun/model_monitoring/batch.py +0 -1095
  293. mlrun/model_monitoring/prometheus.py +0 -219
  294. mlrun/model_monitoring/stores/__init__.py +0 -111
  295. mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -576
  296. mlrun/model_monitoring/stores/model_endpoint_store.py +0 -147
  297. mlrun/model_monitoring/stores/models/__init__.py +0 -27
  298. mlrun/model_monitoring/stores/models/base.py +0 -84
  299. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -384
  300. mlrun/platforms/other.py +0 -306
  301. mlrun-1.6.4rc7.dist-info/METADATA +0 -272
  302. mlrun-1.6.4rc7.dist-info/RECORD +0 -314
  303. {mlrun-1.6.4rc7.dist-info → mlrun-1.7.0.dist-info}/LICENSE +0 -0
  304. {mlrun-1.6.4rc7.dist-info → mlrun-1.7.0.dist-info}/entry_points.txt +0 -0
  305. {mlrun-1.6.4rc7.dist-info → mlrun-1.7.0.dist-info}/top_level.txt +0 -0
@@ -13,14 +13,22 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import hashlib
16
- from dataclasses import dataclass
16
+ import re
17
+ from dataclasses import dataclass, field
17
18
  from enum import Enum, IntEnum
18
19
  from typing import Optional
19
20
 
21
+ import mlrun.common.constants
20
22
  import mlrun.common.helpers
21
23
  from mlrun.common.types import StrEnum
22
24
 
23
25
 
26
+ class MonitoringStrEnum(StrEnum):
27
+ @classmethod
28
+ def list(cls):
29
+ return list(map(lambda c: c.value, cls))
30
+
31
+
24
32
  class EventFieldType:
25
33
  FUNCTION_URI = "function_uri"
26
34
  FUNCTION = "function"
@@ -46,9 +54,11 @@ class EventFieldType:
46
54
  PREDICTIONS = "predictions"
47
55
  NAMED_PREDICTIONS = "named_predictions"
48
56
  ERROR_COUNT = "error_count"
57
+ MODEL_ERROR = "model_error"
49
58
  ENTITIES = "entities"
50
59
  FIRST_REQUEST = "first_request"
51
60
  LAST_REQUEST = "last_request"
61
+ LAST_REQUEST_TIMESTAMP = "last_request_timestamp"
52
62
  METRIC = "metric"
53
63
  METRICS = "metrics"
54
64
  BATCH_INTERVALS_DICT = "batch_intervals_dict"
@@ -72,15 +82,9 @@ class EventFieldType:
72
82
  FEATURE_SET_URI = "monitoring_feature_set_uri"
73
83
  ALGORITHM = "algorithm"
74
84
  VALUE = "value"
75
- DRIFT_DETECTED_THRESHOLD = "drift_detected_threshold"
76
- POSSIBLE_DRIFT_THRESHOLD = "possible_drift_threshold"
77
85
  SAMPLE_PARQUET_PATH = "sample_parquet_path"
78
-
79
-
80
- class MonitoringStrEnum(StrEnum):
81
- @classmethod
82
- def list(cls):
83
- return list(map(lambda c: c.value, cls))
86
+ TIME = "time"
87
+ TABLE_COLUMN = "table_column"
84
88
 
85
89
 
86
90
  class FeatureSetFeatures(MonitoringStrEnum):
@@ -99,12 +103,8 @@ class FeatureSetFeatures(MonitoringStrEnum):
99
103
 
100
104
  class ApplicationEvent:
101
105
  APPLICATION_NAME = "application_name"
102
- CURRENT_STATS = "current_stats"
103
- FEATURE_STATS = "feature_stats"
104
- SAMPLE_PARQUET_PATH = "sample_parquet_path"
105
106
  START_INFER_TIME = "start_infer_time"
106
107
  END_INFER_TIME = "end_infer_time"
107
- LAST_REQUEST = "last_request"
108
108
  ENDPOINT_ID = "endpoint_id"
109
109
  OUTPUT_STREAM_URI = "output_stream_uri"
110
110
 
@@ -114,6 +114,21 @@ class WriterEvent(MonitoringStrEnum):
114
114
  ENDPOINT_ID = "endpoint_id"
115
115
  START_INFER_TIME = "start_infer_time"
116
116
  END_INFER_TIME = "end_infer_time"
117
+ EVENT_KIND = "event_kind" # metric or result
118
+ DATA = "data"
119
+
120
+
121
+ class WriterEventKind(MonitoringStrEnum):
122
+ METRIC = "metric"
123
+ RESULT = "result"
124
+
125
+
126
+ class MetricData(MonitoringStrEnum):
127
+ METRIC_NAME = "metric_name"
128
+ METRIC_VALUE = "metric_value"
129
+
130
+
131
+ class ResultData(MonitoringStrEnum):
117
132
  RESULT_NAME = "result_name"
118
133
  RESULT_VALUE = "result_value"
119
134
  RESULT_KIND = "result_kind"
@@ -138,21 +153,40 @@ class EventKeyMetrics:
138
153
  REAL_TIME = "real_time"
139
154
 
140
155
 
141
- class TimeSeriesTarget:
142
- TSDB = "tsdb"
143
-
144
-
145
- class ModelEndpointTarget:
156
+ class ModelEndpointTarget(MonitoringStrEnum):
146
157
  V3IO_NOSQL = "v3io-nosql"
147
158
  SQL = "sql"
148
159
 
149
160
 
161
+ class StreamKind(MonitoringStrEnum):
162
+ V3IO_STREAM = "v3io_stream"
163
+ KAFKA = "kafka"
164
+
165
+
166
+ class TSDBTarget(MonitoringStrEnum):
167
+ V3IO_TSDB = "v3io-tsdb"
168
+ TDEngine = "tdengine"
169
+
170
+
150
171
  class ProjectSecretKeys:
151
172
  ENDPOINT_STORE_CONNECTION = "MODEL_MONITORING_ENDPOINT_STORE_CONNECTION"
152
173
  ACCESS_KEY = "MODEL_MONITORING_ACCESS_KEY"
153
- PIPELINES_ACCESS_KEY = "MODEL_MONITORING_PIPELINES_ACCESS_KEY"
154
- KAFKA_BOOTSTRAP_SERVERS = "KAFKA_BOOTSTRAP_SERVERS"
155
174
  STREAM_PATH = "STREAM_PATH"
175
+ TSDB_CONNECTION = "TSDB_CONNECTION"
176
+
177
+ @classmethod
178
+ def mandatory_secrets(cls):
179
+ return [
180
+ cls.ENDPOINT_STORE_CONNECTION,
181
+ cls.STREAM_PATH,
182
+ cls.TSDB_CONNECTION,
183
+ ]
184
+
185
+
186
+ class ModelEndpointTargetSchemas(MonitoringStrEnum):
187
+ V3IO = "v3io"
188
+ MYSQL = "mysql"
189
+ SQLITE = "sqlite"
156
190
 
157
191
 
158
192
  class ModelMonitoringStoreKinds:
@@ -162,15 +196,24 @@ class ModelMonitoringStoreKinds:
162
196
 
163
197
  class SchedulingKeys:
164
198
  LAST_ANALYZED = "last_analyzed"
199
+ ENDPOINT_ID = "endpoint_id"
200
+ APPLICATION_NAME = "application_name"
201
+ UID = "uid"
165
202
 
166
203
 
167
204
  class FileTargetKind:
168
205
  ENDPOINTS = "endpoints"
169
206
  EVENTS = "events"
207
+ PREDICTIONS = "predictions"
170
208
  STREAM = "stream"
171
209
  PARQUET = "parquet"
172
210
  APPS_PARQUET = "apps_parquet"
173
211
  LOG_STREAM = "log_stream"
212
+ APP_RESULTS = "app_results"
213
+ APP_METRICS = "app_metrics"
214
+ MONITORING_SCHEDULES = "monitoring_schedules"
215
+ MONITORING_APPLICATION = "monitoring_application"
216
+ ERRORS = "errors"
174
217
 
175
218
 
176
219
  class ModelMonitoringMode(str, Enum):
@@ -184,29 +227,23 @@ class EndpointType(IntEnum):
184
227
  LEAF_EP = 3 # end point that is a child of a router
185
228
 
186
229
 
187
- class PrometheusMetric:
188
- PREDICTIONS_TOTAL = "predictions_total"
189
- MODEL_LATENCY_SECONDS = "model_latency_seconds"
190
- INCOME_FEATURES = "income_features"
191
- ERRORS_TOTAL = "errors_total"
192
- DRIFT_METRICS = "drift_metrics"
193
- DRIFT_STATUS = "drift_status"
230
+ class MonitoringFunctionNames(MonitoringStrEnum):
231
+ STREAM = "model-monitoring-stream"
232
+ APPLICATION_CONTROLLER = "model-monitoring-controller"
233
+ WRITER = "model-monitoring-writer"
194
234
 
195
235
 
196
- class MonitoringFunctionNames:
197
- WRITER = "model-monitoring-writer"
198
- BATCH = "model-monitoring-batch"
199
- APPLICATION_CONTROLLER = "model-monitoring-controller"
200
- STREAM = None
236
+ class V3IOTSDBTables(MonitoringStrEnum):
237
+ APP_RESULTS = "app-results"
238
+ METRICS = "metrics"
239
+ EVENTS = "events"
240
+ ERRORS = "errors"
201
241
 
202
- @staticmethod
203
- def all():
204
- return [
205
- MonitoringFunctionNames.WRITER,
206
- MonitoringFunctionNames.STREAM,
207
- MonitoringFunctionNames.BATCH,
208
- MonitoringFunctionNames.APPLICATION_CONTROLLER,
209
- ]
242
+
243
+ class TDEngineSuperTables(MonitoringStrEnum):
244
+ APP_RESULTS = "app_results"
245
+ METRICS = "metrics"
246
+ PREDICTIONS = "predictions"
210
247
 
211
248
 
212
249
  @dataclass
@@ -252,7 +289,7 @@ class EndpointUID:
252
289
  function_hash_key: str
253
290
  model: str
254
291
  model_version: str
255
- uid: Optional[str] = None
292
+ uid: str = field(init=False)
256
293
 
257
294
  def __post_init__(self):
258
295
  function_ref = (
@@ -285,6 +322,7 @@ class ResultKindApp(Enum):
285
322
  concept_drift = 1
286
323
  model_performance = 2
287
324
  system_performance = 3
325
+ mm_app_anomaly = 4
288
326
 
289
327
 
290
328
  class ResultStatusApp(IntEnum):
@@ -299,9 +337,52 @@ class ResultStatusApp(IntEnum):
299
337
 
300
338
 
301
339
  class ModelMonitoringAppLabel:
302
- KEY = "mlrun__type"
340
+ KEY = mlrun.common.constants.MLRunInternalLabels.mlrun_type
303
341
  VAL = "mlrun__model-monitoring-application"
304
342
 
343
+ def __str__(self) -> str:
344
+ return f"{self.KEY}={self.VAL}"
345
+
305
346
 
306
347
  class ControllerPolicy:
307
348
  BASE_PERIOD = "base_period"
349
+
350
+
351
+ class HistogramDataDriftApplicationConstants:
352
+ NAME = "histogram-data-drift"
353
+ GENERAL_RESULT_NAME = "general_drift"
354
+
355
+
356
+ class PredictionsQueryConstants:
357
+ DEFAULT_AGGREGATION_GRANULARITY = "10m"
358
+ INVOCATIONS = "invocations"
359
+
360
+
361
+ class SpecialApps:
362
+ MLRUN_INFRA = "mlrun-infra"
363
+
364
+
365
+ _RESERVED_FUNCTION_NAMES = MonitoringFunctionNames.list() + [SpecialApps.MLRUN_INFRA]
366
+
367
+
368
+ V3IO_MODEL_MONITORING_DB = "v3io"
369
+
370
+
371
+ class ModelEndpointMonitoringMetricType(StrEnum):
372
+ RESULT = "result"
373
+ METRIC = "metric"
374
+
375
+
376
+ _FQN_PART_PATTERN = r"[a-zA-Z0-9_-]+"
377
+ FQN_PATTERN = (
378
+ rf"^(?P<project>{_FQN_PART_PATTERN})\."
379
+ rf"(?P<app>{_FQN_PART_PATTERN})\."
380
+ rf"(?P<type>{ModelEndpointMonitoringMetricType.RESULT}|{ModelEndpointMonitoringMetricType.METRIC})\."
381
+ rf"(?P<name>{_FQN_PART_PATTERN})$"
382
+ )
383
+ FQN_REGEX = re.compile(FQN_PATTERN)
384
+
385
+ # refer to `mlrun.utils.regex.project_name`
386
+ PROJECT_PATTERN = r"^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$"
387
+
388
+ MODEL_ENDPOINT_ID_PATTERN = r"^[a-zA-Z0-9_-]+$"
@@ -11,12 +11,18 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- #
15
14
 
16
- from typing import List, Optional, Tuple, Union
15
+ from typing import Optional, Union
17
16
 
18
17
  from pydantic import BaseModel
19
18
 
19
+ import mlrun.common.types
20
+
21
+
22
+ class GrafanaColumnType(mlrun.common.types.StrEnum):
23
+ NUMBER = "number"
24
+ STRING = "string"
25
+
20
26
 
21
27
  class GrafanaColumn(BaseModel):
22
28
  text: str
@@ -24,18 +30,16 @@ class GrafanaColumn(BaseModel):
24
30
 
25
31
 
26
32
  class GrafanaNumberColumn(GrafanaColumn):
27
- text: str
28
- type: str = "number"
33
+ type: str = GrafanaColumnType.NUMBER
29
34
 
30
35
 
31
36
  class GrafanaStringColumn(GrafanaColumn):
32
- text: str
33
- type: str = "string"
37
+ type: str = GrafanaColumnType.STRING
34
38
 
35
39
 
36
40
  class GrafanaTable(BaseModel):
37
- columns: List[GrafanaColumn]
38
- rows: List[List[Optional[Union[float, int, str]]]] = []
41
+ columns: list[GrafanaColumn]
42
+ rows: list[list[Optional[Union[float, int, str]]]] = []
39
43
  type: str = "table"
40
44
 
41
45
  def add_row(self, *args):
@@ -49,7 +53,7 @@ class GrafanaDataPoint(BaseModel):
49
53
 
50
54
  class GrafanaTimeSeriesTarget(BaseModel):
51
55
  target: str
52
- datapoints: List[Tuple[float, int]] = []
56
+ datapoints: list[tuple[float, int]] = []
53
57
 
54
58
  def add_data_point(self, data_point: GrafanaDataPoint):
55
59
  self.datapoints.append((data_point.value, data_point.timestamp))
@@ -11,27 +11,35 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- #
15
14
 
16
15
  import enum
17
16
  import json
18
- import typing
19
- from typing import Any, Dict, List, Optional
17
+ from datetime import datetime
18
+ from typing import Any, NamedTuple, Optional, TypeVar
20
19
 
21
- from pydantic import BaseModel, Field, validator
22
- from pydantic.main import Extra
20
+ from pydantic import BaseModel, Extra, Field, constr, validator
23
21
 
22
+ # TODO: remove the unused import below after `mlrun.datastore` and `mlrun.utils` usage is removed.
23
+ # At the moment `make lint` fails if this is removed.
24
24
  import mlrun.common.model_monitoring
25
25
 
26
26
  from ..object import ObjectKind, ObjectSpec, ObjectStatus
27
27
  from .constants import (
28
+ FQN_REGEX,
29
+ MODEL_ENDPOINT_ID_PATTERN,
30
+ PROJECT_PATTERN,
28
31
  EndpointType,
29
32
  EventFieldType,
30
33
  EventKeyMetrics,
31
34
  EventLiveStats,
35
+ ModelEndpointMonitoringMetricType,
32
36
  ModelMonitoringMode,
37
+ ResultKindApp,
38
+ ResultStatusApp,
33
39
  )
34
40
 
41
+ Model = TypeVar("Model", bound=BaseModel)
42
+
35
43
 
36
44
  class ModelMonitoringStoreKinds:
37
45
  # TODO: do changes in examples & demos In 1.5.0 remove
@@ -40,27 +48,26 @@ class ModelMonitoringStoreKinds:
40
48
 
41
49
 
42
50
  class ModelEndpointMetadata(BaseModel):
43
- project: Optional[str] = ""
51
+ project: constr(regex=PROJECT_PATTERN)
52
+ uid: constr(regex=MODEL_ENDPOINT_ID_PATTERN)
44
53
  labels: Optional[dict] = {}
45
- uid: Optional[str] = ""
46
54
 
47
55
  class Config:
48
56
  extra = Extra.allow
49
57
 
50
58
  @classmethod
51
- def from_flat_dict(cls, endpoint_dict: dict, json_parse_values: typing.List = None):
59
+ def from_flat_dict(cls, endpoint_dict: dict, json_parse_values: list = None):
52
60
  """Create a `ModelEndpointMetadata` object from an endpoint dictionary
53
61
 
54
62
  :param endpoint_dict: Model endpoint dictionary.
55
63
  :param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
56
64
  dictionary using json.loads().
57
65
  """
58
- new_object = cls()
59
66
  if json_parse_values is None:
60
67
  json_parse_values = [EventFieldType.LABELS]
61
68
 
62
69
  return _mapping_attributes(
63
- base_model=new_object,
70
+ model_class=cls,
64
71
  flattened_dictionary=endpoint_dict,
65
72
  json_parse_values=json_parse_values,
66
73
  )
@@ -71,8 +78,8 @@ class ModelEndpointSpec(ObjectSpec):
71
78
  model: Optional[str] = "" # <model_name>:<version>
72
79
  model_class: Optional[str] = ""
73
80
  model_uri: Optional[str] = ""
74
- feature_names: Optional[List[str]] = []
75
- label_names: Optional[List[str]] = []
81
+ feature_names: Optional[list[str]] = []
82
+ label_names: Optional[list[str]] = []
76
83
  stream_path: Optional[str] = ""
77
84
  algorithm: Optional[str] = ""
78
85
  monitor_configuration: Optional[dict] = {}
@@ -80,14 +87,13 @@ class ModelEndpointSpec(ObjectSpec):
80
87
  monitoring_mode: Optional[ModelMonitoringMode] = ModelMonitoringMode.disabled.value
81
88
 
82
89
  @classmethod
83
- def from_flat_dict(cls, endpoint_dict: dict, json_parse_values: typing.List = None):
90
+ def from_flat_dict(cls, endpoint_dict: dict, json_parse_values: list = None):
84
91
  """Create a `ModelEndpointSpec` object from an endpoint dictionary
85
92
 
86
93
  :param endpoint_dict: Model endpoint dictionary.
87
94
  :param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
88
95
  dictionary using json.loads().
89
96
  """
90
- new_object = cls()
91
97
  if json_parse_values is None:
92
98
  json_parse_values = [
93
99
  EventFieldType.FEATURE_NAMES,
@@ -95,23 +101,13 @@ class ModelEndpointSpec(ObjectSpec):
95
101
  EventFieldType.MONITOR_CONFIGURATION,
96
102
  ]
97
103
  return _mapping_attributes(
98
- base_model=new_object,
104
+ model_class=cls,
99
105
  flattened_dictionary=endpoint_dict,
100
106
  json_parse_values=json_parse_values,
101
107
  )
102
108
 
103
- @validator("monitor_configuration")
104
- def set_name(cls, monitor_configuration):
105
- return monitor_configuration or {
106
- EventFieldType.DRIFT_DETECTED_THRESHOLD: (
107
- mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.drift_detected
108
- ),
109
- EventFieldType.POSSIBLE_DRIFT_THRESHOLD: (
110
- mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.possible_drift
111
- ),
112
- }
113
-
114
109
  @validator("model_uri")
110
+ @classmethod
115
111
  def validate_model_uri(cls, model_uri):
116
112
  """Validate that the model uri includes the required prefix"""
117
113
  prefix, uri = mlrun.datastore.parse_store_uri(model_uri)
@@ -123,8 +119,8 @@ class ModelEndpointSpec(ObjectSpec):
123
119
 
124
120
 
125
121
  class Histogram(BaseModel):
126
- buckets: List[float]
127
- counts: List[int]
122
+ buckets: list[float]
123
+ counts: list[int]
128
124
 
129
125
 
130
126
  class FeatureValues(BaseModel):
@@ -175,15 +171,15 @@ class ModelEndpointStatus(ObjectStatus):
175
171
  error_count: Optional[int] = 0
176
172
  drift_status: Optional[str] = ""
177
173
  drift_measures: Optional[dict] = {}
178
- metrics: Optional[Dict[str, Dict[str, Any]]] = {
174
+ metrics: Optional[dict[str, dict[str, Any]]] = {
179
175
  EventKeyMetrics.GENERIC: {
180
176
  EventLiveStats.LATENCY_AVG_1H: 0,
181
177
  EventLiveStats.PREDICTIONS_PER_SECOND: 0,
182
178
  }
183
179
  }
184
- features: Optional[List[Features]] = []
185
- children: Optional[List[str]] = []
186
- children_uids: Optional[List[str]] = []
180
+ features: Optional[list[Features]] = []
181
+ children: Optional[list[str]] = []
182
+ children_uids: Optional[list[str]] = []
187
183
  endpoint_type: Optional[EndpointType] = EndpointType.NODE_EP
188
184
  monitoring_feature_set_uri: Optional[str] = ""
189
185
  state: Optional[str] = ""
@@ -192,14 +188,13 @@ class ModelEndpointStatus(ObjectStatus):
192
188
  extra = Extra.allow
193
189
 
194
190
  @classmethod
195
- def from_flat_dict(cls, endpoint_dict: dict, json_parse_values: typing.List = None):
191
+ def from_flat_dict(cls, endpoint_dict: dict, json_parse_values: list = None):
196
192
  """Create a `ModelEndpointStatus` object from an endpoint dictionary
197
193
 
198
194
  :param endpoint_dict: Model endpoint dictionary.
199
195
  :param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
200
196
  dictionary using json.loads().
201
197
  """
202
- new_object = cls()
203
198
  if json_parse_values is None:
204
199
  json_parse_values = [
205
200
  EventFieldType.FEATURE_STATS,
@@ -211,7 +206,7 @@ class ModelEndpointStatus(ObjectStatus):
211
206
  EventFieldType.ENDPOINT_TYPE,
212
207
  ]
213
208
  return _mapping_attributes(
214
- base_model=new_object,
209
+ model_class=cls,
215
210
  flattened_dictionary=endpoint_dict,
216
211
  json_parse_values=json_parse_values,
217
212
  )
@@ -219,22 +214,13 @@ class ModelEndpointStatus(ObjectStatus):
219
214
 
220
215
  class ModelEndpoint(BaseModel):
221
216
  kind: ObjectKind = Field(ObjectKind.model_endpoint, const=True)
222
- metadata: ModelEndpointMetadata = ModelEndpointMetadata()
217
+ metadata: ModelEndpointMetadata
223
218
  spec: ModelEndpointSpec = ModelEndpointSpec()
224
219
  status: ModelEndpointStatus = ModelEndpointStatus()
225
220
 
226
221
  class Config:
227
222
  extra = Extra.allow
228
223
 
229
- def __init__(self, **data: Any):
230
- super().__init__(**data)
231
- if self.metadata.uid is None:
232
- uid = mlrun.common.model_monitoring.create_model_endpoint_uid(
233
- function_uri=self.spec.function_uri,
234
- versioned_model=self.spec.model,
235
- )
236
- self.metadata.uid = str(uid)
237
-
238
224
  def flat_dict(self):
239
225
  """Generate a flattened `ModelEndpoint` dictionary. The flattened dictionary result is important for storing
240
226
  the model endpoint object in the database.
@@ -275,7 +261,7 @@ class ModelEndpoint(BaseModel):
275
261
  return flatten_dict
276
262
 
277
263
  @classmethod
278
- def from_flat_dict(cls, endpoint_dict: dict):
264
+ def from_flat_dict(cls, endpoint_dict: dict) -> "ModelEndpoint":
279
265
  """Create a `ModelEndpoint` object from an endpoint flattened dictionary. Because the provided dictionary
280
266
  is flattened, we pass it as is to the subclasses without splitting the keys into spec, metadata, and status.
281
267
 
@@ -290,24 +276,85 @@ class ModelEndpoint(BaseModel):
290
276
 
291
277
 
292
278
  class ModelEndpointList(BaseModel):
293
- endpoints: List[ModelEndpoint] = []
279
+ endpoints: list[ModelEndpoint] = []
280
+
281
+
282
+ class ModelEndpointMonitoringMetric(BaseModel):
283
+ project: str
284
+ app: str
285
+ type: ModelEndpointMonitoringMetricType
286
+ name: str
287
+ full_name: str
288
+
289
+
290
+ def _compose_full_name(
291
+ *,
292
+ project: str,
293
+ app: str,
294
+ name: str,
295
+ type: ModelEndpointMonitoringMetricType = ModelEndpointMonitoringMetricType.RESULT,
296
+ ) -> str:
297
+ return ".".join([project, app, type, name])
298
+
299
+
300
+ def _parse_metric_fqn_to_monitoring_metric(fqn: str) -> ModelEndpointMonitoringMetric:
301
+ match = FQN_REGEX.fullmatch(fqn)
302
+ if match is None:
303
+ raise ValueError("The fully qualified name is not in the expected format")
304
+ return ModelEndpointMonitoringMetric.parse_obj(
305
+ match.groupdict() | {"full_name": fqn}
306
+ )
307
+
308
+
309
+ class _MetricPoint(NamedTuple):
310
+ timestamp: datetime
311
+ value: float
312
+
313
+
314
+ class _ResultPoint(NamedTuple):
315
+ timestamp: datetime
316
+ value: float
317
+ status: ResultStatusApp
318
+
319
+
320
+ class _ModelEndpointMonitoringMetricValuesBase(BaseModel):
321
+ full_name: str
322
+ type: ModelEndpointMonitoringMetricType
323
+ data: bool
324
+
325
+
326
+ class ModelEndpointMonitoringMetricValues(_ModelEndpointMonitoringMetricValuesBase):
327
+ type: ModelEndpointMonitoringMetricType = ModelEndpointMonitoringMetricType.METRIC
328
+ values: list[_MetricPoint]
329
+ data: bool = True
330
+
331
+
332
+ class ModelEndpointMonitoringResultValues(_ModelEndpointMonitoringMetricValuesBase):
333
+ type: ModelEndpointMonitoringMetricType = ModelEndpointMonitoringMetricType.RESULT
334
+ result_kind: ResultKindApp
335
+ values: list[_ResultPoint]
336
+ data: bool = True
337
+
338
+
339
+ class ModelEndpointMonitoringMetricNoData(_ModelEndpointMonitoringMetricValuesBase):
340
+ full_name: str
341
+ type: ModelEndpointMonitoringMetricType
342
+ data: bool = False
294
343
 
295
344
 
296
345
  def _mapping_attributes(
297
- base_model: BaseModel,
298
- flattened_dictionary: dict,
299
- json_parse_values: typing.List = None,
300
- ):
346
+ model_class: type[Model], flattened_dictionary: dict, json_parse_values: list
347
+ ) -> Model:
301
348
  """Generate a `BaseModel` object with the provided dictionary attributes.
302
349
 
303
- :param base_model: `BaseModel` object (e.g. `ModelEndpointMetadata`).
350
+ :param model_class: `BaseModel` class (e.g. `ModelEndpointMetadata`).
304
351
  :param flattened_dictionary: Flattened dictionary that contains the model endpoint attributes.
305
352
  :param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
306
353
  dictionary using json.loads().
307
354
  """
308
355
  # Get the fields of the provided base model object. These fields will be used to filter to relevent keys
309
356
  # from the flattened dictionary.
310
- wanted_keys = base_model.__fields__.keys()
357
+ wanted_keys = model_class.__fields__.keys()
311
358
 
312
359
  # Generate a filtered flattened dictionary that will be parsed into the BaseModel object
313
360
  dict_to_parse = {}
@@ -321,7 +368,7 @@ def _mapping_attributes(
321
368
  else:
322
369
  dict_to_parse[field_key] = flattened_dictionary[field_key]
323
370
 
324
- return base_model.parse_obj(dict_to_parse)
371
+ return model_class.parse_obj(dict_to_parse)
325
372
 
326
373
 
327
374
  def _json_loads_if_not_none(field: Any) -> Any: