mlrun 1.7.0rc4__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.

Files changed (235) hide show
  1. mlrun/__init__.py +11 -1
  2. mlrun/__main__.py +39 -121
  3. mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
  4. mlrun/alerts/alert.py +248 -0
  5. mlrun/api/schemas/__init__.py +4 -3
  6. mlrun/artifacts/__init__.py +8 -3
  7. mlrun/artifacts/base.py +39 -254
  8. mlrun/artifacts/dataset.py +9 -190
  9. mlrun/artifacts/manager.py +73 -46
  10. mlrun/artifacts/model.py +30 -158
  11. mlrun/artifacts/plots.py +23 -380
  12. mlrun/common/constants.py +73 -1
  13. mlrun/common/db/sql_session.py +3 -2
  14. mlrun/common/formatters/__init__.py +21 -0
  15. mlrun/common/formatters/artifact.py +46 -0
  16. mlrun/common/formatters/base.py +113 -0
  17. mlrun/common/formatters/feature_set.py +44 -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 +11 -1
  23. mlrun/{runtimes → common/runtimes}/constants.py +32 -4
  24. mlrun/common/schemas/__init__.py +31 -4
  25. mlrun/common/schemas/alert.py +202 -0
  26. mlrun/common/schemas/api_gateway.py +196 -0
  27. mlrun/common/schemas/artifact.py +28 -1
  28. mlrun/common/schemas/auth.py +13 -2
  29. mlrun/common/schemas/client_spec.py +2 -1
  30. mlrun/common/schemas/common.py +7 -4
  31. mlrun/common/schemas/constants.py +3 -0
  32. mlrun/common/schemas/feature_store.py +58 -28
  33. mlrun/common/schemas/frontend_spec.py +8 -0
  34. mlrun/common/schemas/function.py +11 -0
  35. mlrun/common/schemas/hub.py +7 -9
  36. mlrun/common/schemas/model_monitoring/__init__.py +21 -4
  37. mlrun/common/schemas/model_monitoring/constants.py +136 -42
  38. mlrun/common/schemas/model_monitoring/grafana.py +9 -5
  39. mlrun/common/schemas/model_monitoring/model_endpoints.py +89 -41
  40. mlrun/common/schemas/notification.py +69 -12
  41. mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
  42. mlrun/common/schemas/pipeline.py +7 -0
  43. mlrun/common/schemas/project.py +67 -16
  44. mlrun/common/schemas/runs.py +17 -0
  45. mlrun/common/schemas/schedule.py +1 -1
  46. mlrun/common/schemas/workflow.py +10 -2
  47. mlrun/common/types.py +14 -1
  48. mlrun/config.py +233 -58
  49. mlrun/data_types/data_types.py +11 -1
  50. mlrun/data_types/spark.py +5 -4
  51. mlrun/data_types/to_pandas.py +75 -34
  52. mlrun/datastore/__init__.py +8 -10
  53. mlrun/datastore/alibaba_oss.py +131 -0
  54. mlrun/datastore/azure_blob.py +131 -43
  55. mlrun/datastore/base.py +107 -47
  56. mlrun/datastore/datastore.py +17 -7
  57. mlrun/datastore/datastore_profile.py +91 -7
  58. mlrun/datastore/dbfs_store.py +3 -7
  59. mlrun/datastore/filestore.py +1 -3
  60. mlrun/datastore/google_cloud_storage.py +92 -32
  61. mlrun/datastore/hdfs.py +5 -0
  62. mlrun/datastore/inmem.py +6 -3
  63. mlrun/datastore/redis.py +3 -2
  64. mlrun/datastore/s3.py +30 -12
  65. mlrun/datastore/snowflake_utils.py +45 -0
  66. mlrun/datastore/sources.py +274 -59
  67. mlrun/datastore/spark_utils.py +30 -0
  68. mlrun/datastore/store_resources.py +9 -7
  69. mlrun/datastore/storeytargets.py +151 -0
  70. mlrun/datastore/targets.py +387 -119
  71. mlrun/datastore/utils.py +68 -5
  72. mlrun/datastore/v3io.py +28 -50
  73. mlrun/db/auth_utils.py +152 -0
  74. mlrun/db/base.py +245 -20
  75. mlrun/db/factory.py +1 -4
  76. mlrun/db/httpdb.py +909 -231
  77. mlrun/db/nopdb.py +279 -14
  78. mlrun/errors.py +35 -5
  79. mlrun/execution.py +111 -38
  80. mlrun/feature_store/__init__.py +0 -2
  81. mlrun/feature_store/api.py +46 -53
  82. mlrun/feature_store/common.py +6 -11
  83. mlrun/feature_store/feature_set.py +48 -23
  84. mlrun/feature_store/feature_vector.py +13 -2
  85. mlrun/feature_store/ingestion.py +7 -6
  86. mlrun/feature_store/retrieval/base.py +9 -4
  87. mlrun/feature_store/retrieval/dask_merger.py +2 -0
  88. mlrun/feature_store/retrieval/job.py +13 -4
  89. mlrun/feature_store/retrieval/local_merger.py +2 -0
  90. mlrun/feature_store/retrieval/spark_merger.py +24 -32
  91. mlrun/feature_store/steps.py +38 -19
  92. mlrun/features.py +6 -14
  93. mlrun/frameworks/_common/plan.py +3 -3
  94. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
  95. mlrun/frameworks/_ml_common/plan.py +1 -1
  96. mlrun/frameworks/auto_mlrun/auto_mlrun.py +2 -2
  97. mlrun/frameworks/lgbm/__init__.py +1 -1
  98. mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
  99. mlrun/frameworks/lgbm/model_handler.py +1 -1
  100. mlrun/frameworks/parallel_coordinates.py +4 -4
  101. mlrun/frameworks/pytorch/__init__.py +2 -2
  102. mlrun/frameworks/sklearn/__init__.py +1 -1
  103. mlrun/frameworks/sklearn/mlrun_interface.py +13 -3
  104. mlrun/frameworks/tf_keras/__init__.py +5 -2
  105. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
  106. mlrun/frameworks/tf_keras/mlrun_interface.py +2 -2
  107. mlrun/frameworks/xgboost/__init__.py +1 -1
  108. mlrun/k8s_utils.py +57 -12
  109. mlrun/launcher/__init__.py +1 -1
  110. mlrun/launcher/base.py +6 -5
  111. mlrun/launcher/client.py +13 -11
  112. mlrun/launcher/factory.py +1 -1
  113. mlrun/launcher/local.py +15 -5
  114. mlrun/launcher/remote.py +10 -3
  115. mlrun/lists.py +6 -2
  116. mlrun/model.py +297 -48
  117. mlrun/model_monitoring/__init__.py +1 -1
  118. mlrun/model_monitoring/api.py +152 -357
  119. mlrun/model_monitoring/applications/__init__.py +10 -0
  120. mlrun/model_monitoring/applications/_application_steps.py +190 -0
  121. mlrun/model_monitoring/applications/base.py +108 -0
  122. mlrun/model_monitoring/applications/context.py +341 -0
  123. mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
  124. mlrun/model_monitoring/applications/histogram_data_drift.py +227 -91
  125. mlrun/model_monitoring/applications/results.py +99 -0
  126. mlrun/model_monitoring/controller.py +130 -303
  127. mlrun/model_monitoring/{stores/models/sqlite.py → db/__init__.py} +5 -10
  128. mlrun/model_monitoring/db/stores/__init__.py +136 -0
  129. mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
  130. mlrun/model_monitoring/db/stores/base/store.py +213 -0
  131. mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
  132. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
  133. mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
  134. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -0
  135. mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
  136. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +659 -0
  137. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
  138. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
  139. mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
  140. mlrun/model_monitoring/db/tsdb/base.py +448 -0
  141. mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
  142. mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
  143. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +298 -0
  144. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
  145. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +522 -0
  146. mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
  147. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
  148. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
  149. mlrun/model_monitoring/features_drift_table.py +34 -22
  150. mlrun/model_monitoring/helpers.py +177 -39
  151. mlrun/model_monitoring/model_endpoint.py +3 -2
  152. mlrun/model_monitoring/stream_processing.py +165 -398
  153. mlrun/model_monitoring/tracking_policy.py +7 -1
  154. mlrun/model_monitoring/writer.py +161 -125
  155. mlrun/package/packagers/default_packager.py +2 -2
  156. mlrun/package/packagers_manager.py +1 -0
  157. mlrun/package/utils/_formatter.py +2 -2
  158. mlrun/platforms/__init__.py +11 -10
  159. mlrun/platforms/iguazio.py +67 -228
  160. mlrun/projects/__init__.py +6 -1
  161. mlrun/projects/operations.py +47 -20
  162. mlrun/projects/pipelines.py +396 -249
  163. mlrun/projects/project.py +1176 -406
  164. mlrun/render.py +28 -22
  165. mlrun/run.py +208 -181
  166. mlrun/runtimes/__init__.py +76 -11
  167. mlrun/runtimes/base.py +54 -24
  168. mlrun/runtimes/daskjob.py +9 -2
  169. mlrun/runtimes/databricks_job/databricks_runtime.py +1 -0
  170. mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
  171. mlrun/runtimes/funcdoc.py +1 -29
  172. mlrun/runtimes/kubejob.py +34 -128
  173. mlrun/runtimes/local.py +39 -10
  174. mlrun/runtimes/mpijob/__init__.py +0 -20
  175. mlrun/runtimes/mpijob/abstract.py +8 -8
  176. mlrun/runtimes/mpijob/v1.py +1 -1
  177. mlrun/runtimes/nuclio/__init__.py +1 -0
  178. mlrun/runtimes/nuclio/api_gateway.py +769 -0
  179. mlrun/runtimes/nuclio/application/__init__.py +15 -0
  180. mlrun/runtimes/nuclio/application/application.py +758 -0
  181. mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
  182. mlrun/runtimes/nuclio/function.py +188 -68
  183. mlrun/runtimes/nuclio/serving.py +57 -60
  184. mlrun/runtimes/pod.py +191 -58
  185. mlrun/runtimes/remotesparkjob.py +11 -8
  186. mlrun/runtimes/sparkjob/spark3job.py +17 -18
  187. mlrun/runtimes/utils.py +40 -73
  188. mlrun/secrets.py +6 -2
  189. mlrun/serving/__init__.py +8 -1
  190. mlrun/serving/remote.py +2 -3
  191. mlrun/serving/routers.py +89 -64
  192. mlrun/serving/server.py +54 -26
  193. mlrun/serving/states.py +187 -56
  194. mlrun/serving/utils.py +19 -11
  195. mlrun/serving/v2_serving.py +136 -63
  196. mlrun/track/tracker.py +2 -1
  197. mlrun/track/trackers/mlflow_tracker.py +5 -0
  198. mlrun/utils/async_http.py +26 -6
  199. mlrun/utils/db.py +18 -0
  200. mlrun/utils/helpers.py +375 -105
  201. mlrun/utils/http.py +2 -2
  202. mlrun/utils/logger.py +75 -9
  203. mlrun/utils/notifications/notification/__init__.py +14 -10
  204. mlrun/utils/notifications/notification/base.py +48 -0
  205. mlrun/utils/notifications/notification/console.py +2 -0
  206. mlrun/utils/notifications/notification/git.py +24 -1
  207. mlrun/utils/notifications/notification/ipython.py +2 -0
  208. mlrun/utils/notifications/notification/slack.py +96 -21
  209. mlrun/utils/notifications/notification/webhook.py +63 -2
  210. mlrun/utils/notifications/notification_pusher.py +146 -16
  211. mlrun/utils/regex.py +9 -0
  212. mlrun/utils/retryer.py +3 -2
  213. mlrun/utils/v3io_clients.py +2 -3
  214. mlrun/utils/version/version.json +2 -2
  215. mlrun-1.7.2.dist-info/METADATA +390 -0
  216. mlrun-1.7.2.dist-info/RECORD +351 -0
  217. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/WHEEL +1 -1
  218. mlrun/feature_store/retrieval/conversion.py +0 -271
  219. mlrun/kfpops.py +0 -868
  220. mlrun/model_monitoring/application.py +0 -310
  221. mlrun/model_monitoring/batch.py +0 -974
  222. mlrun/model_monitoring/controller_handler.py +0 -37
  223. mlrun/model_monitoring/prometheus.py +0 -216
  224. mlrun/model_monitoring/stores/__init__.py +0 -111
  225. mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -574
  226. mlrun/model_monitoring/stores/model_endpoint_store.py +0 -145
  227. mlrun/model_monitoring/stores/models/__init__.py +0 -27
  228. mlrun/model_monitoring/stores/models/base.py +0 -84
  229. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
  230. mlrun/platforms/other.py +0 -305
  231. mlrun-1.7.0rc4.dist-info/METADATA +0 -269
  232. mlrun-1.7.0rc4.dist-info/RECORD +0 -321
  233. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/LICENSE +0 -0
  234. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/entry_points.txt +0 -0
  235. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/top_level.txt +0 -0
@@ -21,9 +21,34 @@ import plotly.graph_objects as go
21
21
  from plotly.subplots import make_subplots
22
22
 
23
23
  import mlrun.common.schemas.model_monitoring
24
+ from mlrun.artifacts import PlotlyArtifact
24
25
 
25
26
  # A type for representing a drift result, a tuple of the status and the drift mean:
26
- DriftResultType = tuple[mlrun.common.schemas.model_monitoring.DriftStatus, float]
27
+ DriftResultType = tuple[
28
+ mlrun.common.schemas.model_monitoring.constants.ResultStatusApp, float
29
+ ]
30
+
31
+
32
+ class _PlotlyTableArtifact(PlotlyArtifact):
33
+ """A custom class for plotly table artifacts"""
34
+
35
+ @staticmethod
36
+ def _disable_table_dragging(figure_html: str) -> str:
37
+ """
38
+ Disable the table columns dragging by adding the following
39
+ JavaScript code
40
+ """
41
+ start, end = figure_html.rsplit(";", 1)
42
+ middle = (
43
+ ';for (const element of document.getElementsByClassName("table")) '
44
+ '{element.style.pointerEvents = "none";}'
45
+ )
46
+ figure_html = start + middle + end
47
+ return figure_html
48
+
49
+ def get_body(self) -> str:
50
+ """Get the adjusted HTML representation of the figure"""
51
+ return self._disable_table_dragging(super().get_body())
27
52
 
28
53
 
29
54
  class FeaturesDriftTablePlot:
@@ -62,9 +87,9 @@ class FeaturesDriftTablePlot:
62
87
 
63
88
  # Status configurations:
64
89
  _STATUS_COLORS = {
65
- mlrun.common.schemas.model_monitoring.DriftStatus.NO_DRIFT: "rgb(0,176,80)", # Green
66
- mlrun.common.schemas.model_monitoring.DriftStatus.POSSIBLE_DRIFT: "rgb(255,192,0)", # Orange
67
- mlrun.common.schemas.model_monitoring.DriftStatus.DRIFT_DETECTED: "rgb(208,0,106)", # Magenta
90
+ mlrun.common.schemas.model_monitoring.constants.ResultStatusApp.no_detection: "rgb(0,176,80)", # Green
91
+ mlrun.common.schemas.model_monitoring.constants.ResultStatusApp.potential_detection: "rgb(255,192,0)", # Orange
92
+ mlrun.common.schemas.model_monitoring.constants.ResultStatusApp.detected: "rgb(208,0,106)", # Magenta
68
93
  }
69
94
 
70
95
  # Font configurations:
@@ -97,7 +122,7 @@ class FeaturesDriftTablePlot:
97
122
  inputs_statistics: dict,
98
123
  metrics: dict[str, Union[dict, float]],
99
124
  drift_results: dict[str, DriftResultType],
100
- ) -> str:
125
+ ) -> _PlotlyTableArtifact:
101
126
  """
102
127
  Produce the html code of the table plot with the given information and the stored configurations in the class.
103
128
 
@@ -106,9 +131,8 @@ class FeaturesDriftTablePlot:
106
131
  :param metrics: The drift detection metrics calculated on the sample set and inputs.
107
132
  :param drift_results: The drift results per feature according to the rules of the monitor.
108
133
 
109
- :return: The full path to the html file of the plot.
134
+ :return: The drift table as a plotly artifact.
110
135
  """
111
- # Plot the drift table:
112
136
  figure = self._plot(
113
137
  features=list(inputs_statistics.keys()),
114
138
  sample_set_statistics=sample_set_statistics,
@@ -116,19 +140,7 @@ class FeaturesDriftTablePlot:
116
140
  metrics=metrics,
117
141
  drift_results=drift_results,
118
142
  )
119
-
120
- # Get its HTML representation:
121
- figure_html = figure.to_html()
122
-
123
- # Turn off the table columns dragging by injecting the following JavaScript code:
124
- start, end = figure_html.rsplit(";", 1)
125
- middle = (
126
- ';for (const element of document.getElementsByClassName("table")) '
127
- '{element.style.pointerEvents = "none";}'
128
- )
129
- figure_html = start + middle + end
130
-
131
- return figure_html
143
+ return _PlotlyTableArtifact(figure=figure, key="drift_table_plot")
132
144
 
133
145
  def _read_columns_names(self, statistics_dictionary: dict, drift_metrics: dict):
134
146
  """
@@ -366,10 +378,10 @@ class FeaturesDriftTablePlot:
366
378
  bins = np.array(bins)
367
379
  if bins[0] == -sys.float_info.max:
368
380
  bins[0] = bins[1] - (bins[2] - bins[1])
369
- hovertext[0] = f"(-∞, {bins[1]})"
381
+ hovertext[0] = f"(-inf, {bins[1]})"
370
382
  if bins[-1] == sys.float_info.max:
371
383
  bins[-1] = bins[-2] + (bins[-2] - bins[-3])
372
- hovertext[-1] = f"({bins[-2]}, )"
384
+ hovertext[-1] = f"({bins[-2]}, inf)"
373
385
  # Center the bins (leave the first one):
374
386
  bins = 0.5 * (bins[:-1] + bins[1:])
375
387
  # Plot the histogram as a line with filled background below it:
@@ -15,19 +15,25 @@
15
15
  import datetime
16
16
  import typing
17
17
 
18
- import mlrun
19
- import mlrun.common.model_monitoring.helpers
20
- import mlrun.common.schemas
21
- from mlrun.common.schemas.model_monitoring import (
22
- EventFieldType,
23
- )
24
- from mlrun.model_monitoring.model_endpoint import ModelEndpoint
25
- from mlrun.utils import logger
18
+ import numpy as np
19
+ import pandas as pd
26
20
 
27
21
  if typing.TYPE_CHECKING:
28
22
  from mlrun.db.base import RunDBInterface
29
23
  from mlrun.projects import MlrunProject
24
+
25
+ import mlrun
26
+ import mlrun.artifacts
27
+ import mlrun.common.model_monitoring.helpers
30
28
  import mlrun.common.schemas.model_monitoring.constants as mm_constants
29
+ import mlrun.data_types.infer
30
+ import mlrun.model_monitoring
31
+ from mlrun.common.schemas.model_monitoring.model_endpoints import (
32
+ ModelEndpointMonitoringMetric,
33
+ _compose_full_name,
34
+ )
35
+ from mlrun.model_monitoring.model_endpoint import ModelEndpoint
36
+ from mlrun.utils import logger
31
37
 
32
38
 
33
39
  class _BatchDict(typing.TypedDict):
@@ -36,34 +42,33 @@ class _BatchDict(typing.TypedDict):
36
42
  days: int
37
43
 
38
44
 
39
- class _MLRunNoRunsFoundError(Exception):
40
- pass
41
-
42
-
43
45
  def get_stream_path(
44
- project: str = None,
46
+ project: str,
45
47
  function_name: str = mm_constants.MonitoringFunctionNames.STREAM,
46
- ):
48
+ stream_uri: typing.Optional[str] = None,
49
+ ) -> str:
47
50
  """
48
51
  Get stream path from the project secret. If wasn't set, take it from the system configurations
49
52
 
50
53
  :param project: Project name.
51
- :param function_name: Application name. Default is model_monitoring_stream.
54
+ :param function_name: Application name. Default is model_monitoring_stream.
55
+ :param stream_uri: Stream URI. If provided, it will be used instead of the one from the project secret.
52
56
 
53
57
  :return: Monitoring stream path to the relevant application.
54
58
  """
55
59
 
56
- stream_uri = mlrun.get_secret_or_env(
57
- mlrun.common.schemas.model_monitoring.ProjectSecretKeys.STREAM_PATH
58
- if function_name is mm_constants.MonitoringFunctionNames.STREAM
59
- else ""
60
- ) or mlrun.mlconf.get_model_monitoring_file_target_path(
61
- project=project,
62
- kind=mlrun.common.schemas.model_monitoring.FileTargetKind.STREAM,
63
- target="online",
64
- function_name=function_name,
60
+ stream_uri = stream_uri or mlrun.get_secret_or_env(
61
+ mm_constants.ProjectSecretKeys.STREAM_PATH
65
62
  )
66
63
 
64
+ if not stream_uri or stream_uri == "v3io":
65
+ stream_uri = mlrun.mlconf.get_model_monitoring_file_target_path(
66
+ project=project,
67
+ kind=mm_constants.FileTargetKind.STREAM,
68
+ target="online",
69
+ function_name=function_name,
70
+ )
71
+
67
72
  return mlrun.common.model_monitoring.helpers.parse_monitoring_stream_path(
68
73
  stream_uri=stream_uri, project=project, function_name=function_name
69
74
  )
@@ -71,7 +76,7 @@ def get_stream_path(
71
76
 
72
77
  def get_monitoring_parquet_path(
73
78
  project: "MlrunProject",
74
- kind: str = mlrun.common.schemas.model_monitoring.FileTargetKind.PARQUET,
79
+ kind: str = mm_constants.FileTargetKind.PARQUET,
75
80
  ) -> str:
76
81
  """Get model monitoring parquet target for the current project and kind. The parquet target path is based on the
77
82
  project artifact path. If project artifact path is not defined, the parquet target path will be based on MLRun
@@ -93,7 +98,7 @@ def get_monitoring_parquet_path(
93
98
  return parquet_path
94
99
 
95
100
 
96
- def get_connection_string(secret_provider: typing.Callable = None) -> str:
101
+ def get_connection_string(secret_provider: typing.Callable[[str], str] = None) -> str:
97
102
  """Get endpoint store connection string from the project secret. If wasn't set, take it from the system
98
103
  configurations.
99
104
 
@@ -103,12 +108,24 @@ def get_connection_string(secret_provider: typing.Callable = None) -> str:
103
108
 
104
109
  """
105
110
 
106
- return (
107
- mlrun.get_secret_or_env(
108
- key=mlrun.common.schemas.model_monitoring.ProjectSecretKeys.ENDPOINT_STORE_CONNECTION,
109
- secret_provider=secret_provider,
110
- )
111
- or mlrun.mlconf.model_endpoint_monitoring.endpoint_store_connection
111
+ return mlrun.get_secret_or_env(
112
+ key=mm_constants.ProjectSecretKeys.ENDPOINT_STORE_CONNECTION,
113
+ secret_provider=secret_provider,
114
+ )
115
+
116
+
117
+ def get_tsdb_connection_string(
118
+ secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
119
+ ) -> str:
120
+ """Get TSDB connection string from the project secret. If wasn't set, take it from the system
121
+ configurations.
122
+ :param secret_provider: An optional secret provider to get the connection string secret.
123
+ :return: Valid TSDB connection string.
124
+ """
125
+
126
+ return mlrun.get_secret_or_env(
127
+ key=mm_constants.ProjectSecretKeys.TSDB_CONNECTION,
128
+ secret_provider=secret_provider,
112
129
  )
113
130
 
114
131
 
@@ -158,7 +175,7 @@ def _get_monitoring_time_window_from_controller_run(
158
175
  def update_model_endpoint_last_request(
159
176
  project: str,
160
177
  model_endpoint: ModelEndpoint,
161
- current_request: datetime,
178
+ current_request: datetime.datetime,
162
179
  db: "RunDBInterface",
163
180
  ) -> None:
164
181
  """
@@ -169,7 +186,8 @@ def update_model_endpoint_last_request(
169
186
  :param current_request: current request time
170
187
  :param db: DB interface.
171
188
  """
172
- if model_endpoint.spec.stream_path != "":
189
+ is_model_server_endpoint = model_endpoint.spec.stream_path != ""
190
+ if is_model_server_endpoint:
173
191
  current_request = current_request.isoformat()
174
192
  logger.info(
175
193
  "Update model endpoint last request time (EP with serving)",
@@ -181,14 +199,15 @@ def update_model_endpoint_last_request(
181
199
  db.patch_model_endpoint(
182
200
  project=project,
183
201
  endpoint_id=model_endpoint.metadata.uid,
184
- attributes={EventFieldType.LAST_REQUEST: current_request},
202
+ attributes={mm_constants.EventFieldType.LAST_REQUEST: current_request},
185
203
  )
186
- else:
204
+ else: # model endpoint without any serving function - close the window "manually"
187
205
  try:
188
206
  time_window = _get_monitoring_time_window_from_controller_run(project, db)
189
207
  except mlrun.errors.MLRunNotFoundError:
190
- logger.debug(
191
- "Not bumping model endpoint last request time - the monitoring controller isn't deployed yet"
208
+ logger.warn(
209
+ "Not bumping model endpoint last request time - the monitoring controller isn't deployed yet.\n"
210
+ "Call `project.enable_model_monitoring()` first."
192
211
  )
193
212
  return
194
213
 
@@ -210,5 +229,124 @@ def update_model_endpoint_last_request(
210
229
  db.patch_model_endpoint(
211
230
  project=project,
212
231
  endpoint_id=model_endpoint.metadata.uid,
213
- attributes={EventFieldType.LAST_REQUEST: bumped_last_request},
232
+ attributes={mm_constants.EventFieldType.LAST_REQUEST: bumped_last_request},
214
233
  )
234
+
235
+
236
+ def calculate_inputs_statistics(
237
+ sample_set_statistics: dict, inputs: pd.DataFrame
238
+ ) -> mlrun.common.model_monitoring.helpers.FeatureStats:
239
+ """
240
+ Calculate the inputs data statistics for drift monitoring purpose.
241
+
242
+ :param sample_set_statistics: The sample set (stored end point's dataset to reference) statistics. The bins of the
243
+ histograms of each feature will be used to recalculate the histograms of the inputs.
244
+ :param inputs: The inputs to calculate their statistics and later on - the drift with respect to the
245
+ sample set.
246
+
247
+ :returns: The calculated statistics of the inputs data.
248
+ """
249
+
250
+ # Use `DFDataInfer` to calculate the statistics over the inputs:
251
+ inputs_statistics = mlrun.data_types.infer.DFDataInfer.get_stats(
252
+ df=inputs, options=mlrun.data_types.infer.InferOptions.Histogram
253
+ )
254
+
255
+ # Recalculate the histograms over the bins that are set in the sample-set of the end point:
256
+ for feature in list(inputs_statistics):
257
+ if feature in sample_set_statistics:
258
+ counts, bins = np.histogram(
259
+ inputs[feature].to_numpy(),
260
+ bins=sample_set_statistics[feature]["hist"][1],
261
+ )
262
+ inputs_statistics[feature]["hist"] = [
263
+ counts.tolist(),
264
+ bins.tolist(),
265
+ ]
266
+ else:
267
+ # If the feature is not in the sample set and doesn't have a histogram, remove it from the statistics:
268
+ inputs_statistics.pop(feature)
269
+
270
+ return inputs_statistics
271
+
272
+
273
+ def get_endpoint_record(
274
+ project: str,
275
+ endpoint_id: str,
276
+ secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
277
+ ) -> dict[str, typing.Any]:
278
+ model_endpoint_store = mlrun.model_monitoring.get_store_object(
279
+ project=project, secret_provider=secret_provider
280
+ )
281
+ return model_endpoint_store.get_model_endpoint(endpoint_id=endpoint_id)
282
+
283
+
284
+ def get_result_instance_fqn(
285
+ model_endpoint_id: str, app_name: str, result_name: str
286
+ ) -> str:
287
+ return f"{model_endpoint_id}.{app_name}.result.{result_name}"
288
+
289
+
290
+ def get_default_result_instance_fqn(model_endpoint_id: str) -> str:
291
+ return get_result_instance_fqn(
292
+ model_endpoint_id,
293
+ mm_constants.HistogramDataDriftApplicationConstants.NAME,
294
+ mm_constants.HistogramDataDriftApplicationConstants.GENERAL_RESULT_NAME,
295
+ )
296
+
297
+
298
+ def get_invocations_fqn(project: str) -> str:
299
+ return _compose_full_name(
300
+ project=project,
301
+ app=mm_constants.SpecialApps.MLRUN_INFRA,
302
+ name=mm_constants.PredictionsQueryConstants.INVOCATIONS,
303
+ type=mm_constants.ModelEndpointMonitoringMetricType.METRIC,
304
+ )
305
+
306
+
307
+ def get_invocations_metric(project: str) -> ModelEndpointMonitoringMetric:
308
+ """
309
+ Return the invocations metric of any model endpoint in the given project.
310
+
311
+ :param project: The project name.
312
+ :returns: The model monitoring metric object.
313
+ """
314
+ return ModelEndpointMonitoringMetric(
315
+ project=project,
316
+ app=mm_constants.SpecialApps.MLRUN_INFRA,
317
+ type=mm_constants.ModelEndpointMonitoringMetricType.METRIC,
318
+ name=mm_constants.PredictionsQueryConstants.INVOCATIONS,
319
+ full_name=get_invocations_fqn(project),
320
+ )
321
+
322
+
323
+ def enrich_model_endpoint_with_model_uri(
324
+ model_endpoint: ModelEndpoint,
325
+ model_obj: mlrun.artifacts.ModelArtifact,
326
+ ):
327
+ """
328
+ Enrich the model endpoint object with the model uri from the model object. We will use a unique reference
329
+ to the model object that includes the project, db_key, iter, and tree.
330
+ In addition, we verify that the model object is of type `ModelArtifact`.
331
+
332
+ :param model_endpoint: An object representing the model endpoint that will be enriched with the model uri.
333
+ :param model_obj: An object representing the model artifact.
334
+
335
+ :raise: `MLRunInvalidArgumentError` if the model object is not of type `ModelArtifact`.
336
+ """
337
+ mlrun.utils.helpers.verify_field_of_type(
338
+ field_name="model_endpoint.spec.model_uri",
339
+ field_value=model_obj,
340
+ expected_type=mlrun.artifacts.ModelArtifact,
341
+ )
342
+
343
+ # Update model_uri with a unique reference to handle future changes
344
+ model_artifact_uri = mlrun.utils.helpers.generate_artifact_uri(
345
+ project=model_endpoint.metadata.project,
346
+ key=model_obj.db_key,
347
+ iter=model_obj.iter,
348
+ tree=model_obj.tree,
349
+ )
350
+ model_endpoint.spec.model_uri = mlrun.datastore.get_store_uri(
351
+ kind=mlrun.utils.helpers.StorePrefix.Model, uri=model_artifact_uri
352
+ )
@@ -17,6 +17,7 @@ from dataclasses import dataclass, field
17
17
  from typing import Any
18
18
 
19
19
  import mlrun.model
20
+ from mlrun.common.model_monitoring.helpers import FeatureStats
20
21
  from mlrun.common.schemas.model_monitoring.constants import (
21
22
  EndpointType,
22
23
  EventKeyMetrics,
@@ -42,8 +43,8 @@ class ModelEndpointSpec(mlrun.model.ModelObj):
42
43
 
43
44
  @dataclass
44
45
  class ModelEndpointStatus(mlrun.model.ModelObj):
45
- feature_stats: dict = field(default_factory=dict)
46
- current_stats: dict = field(default_factory=dict)
46
+ feature_stats: FeatureStats = field(default_factory=dict)
47
+ current_stats: FeatureStats = field(default_factory=dict)
47
48
  first_request: str = ""
48
49
  last_request: str = ""
49
50
  error_count: int = 0