mlrun 1.7.2rc3__py3-none-any.whl → 1.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mlrun might be problematic. Click here for more details.

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