mlrun 1.3.2rc1__py3-none-any.whl → 1.3.2rc2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/api/api/deps.py +14 -1
- mlrun/api/api/endpoints/frontend_spec.py +0 -2
- mlrun/api/api/endpoints/functions.py +15 -27
- mlrun/api/api/endpoints/grafana_proxy.py +435 -74
- mlrun/api/api/endpoints/healthz.py +5 -18
- mlrun/api/api/endpoints/model_endpoints.py +33 -37
- mlrun/api/api/utils.py +6 -13
- mlrun/api/crud/__init__.py +14 -16
- mlrun/api/crud/logs.py +5 -7
- mlrun/api/crud/model_monitoring/__init__.py +2 -2
- mlrun/api/crud/model_monitoring/model_endpoint_store.py +847 -0
- mlrun/api/crud/model_monitoring/model_endpoints.py +105 -328
- mlrun/api/crud/pipelines.py +2 -3
- mlrun/api/db/sqldb/models/models_mysql.py +52 -19
- mlrun/api/db/sqldb/models/models_sqlite.py +52 -19
- mlrun/api/db/sqldb/session.py +19 -26
- mlrun/api/schemas/__init__.py +2 -0
- mlrun/api/schemas/constants.py +0 -13
- mlrun/api/schemas/frontend_spec.py +0 -1
- mlrun/api/schemas/model_endpoints.py +38 -195
- mlrun/api/schemas/schedule.py +2 -2
- mlrun/api/utils/clients/log_collector.py +5 -0
- mlrun/builder.py +9 -41
- mlrun/config.py +1 -76
- mlrun/data_types/__init__.py +1 -6
- mlrun/data_types/data_types.py +1 -3
- mlrun/datastore/__init__.py +2 -9
- mlrun/datastore/sources.py +20 -25
- mlrun/datastore/store_resources.py +1 -1
- mlrun/datastore/targets.py +34 -67
- mlrun/datastore/utils.py +4 -26
- mlrun/db/base.py +2 -4
- mlrun/db/filedb.py +5 -13
- mlrun/db/httpdb.py +32 -64
- mlrun/db/sqldb.py +2 -4
- mlrun/errors.py +0 -5
- mlrun/execution.py +0 -2
- mlrun/feature_store/api.py +8 -24
- mlrun/feature_store/feature_set.py +6 -28
- mlrun/feature_store/feature_vector.py +0 -2
- mlrun/feature_store/ingestion.py +11 -8
- mlrun/feature_store/retrieval/base.py +43 -271
- mlrun/feature_store/retrieval/dask_merger.py +153 -55
- mlrun/feature_store/retrieval/job.py +3 -12
- mlrun/feature_store/retrieval/local_merger.py +130 -48
- mlrun/feature_store/retrieval/spark_merger.py +125 -126
- mlrun/features.py +2 -7
- mlrun/model_monitoring/constants.py +6 -48
- mlrun/model_monitoring/helpers.py +35 -118
- mlrun/model_monitoring/model_monitoring_batch.py +260 -293
- mlrun/model_monitoring/stream_processing_fs.py +253 -220
- mlrun/platforms/iguazio.py +0 -33
- mlrun/projects/project.py +72 -34
- mlrun/runtimes/base.py +0 -5
- mlrun/runtimes/daskjob.py +0 -2
- mlrun/runtimes/function.py +3 -29
- mlrun/runtimes/kubejob.py +15 -39
- mlrun/runtimes/local.py +45 -7
- mlrun/runtimes/mpijob/abstract.py +0 -2
- mlrun/runtimes/mpijob/v1.py +0 -2
- mlrun/runtimes/pod.py +0 -2
- mlrun/runtimes/remotesparkjob.py +0 -2
- mlrun/runtimes/serving.py +0 -6
- mlrun/runtimes/sparkjob/abstract.py +2 -39
- mlrun/runtimes/sparkjob/spark3job.py +0 -2
- mlrun/serving/__init__.py +1 -2
- mlrun/serving/routers.py +35 -35
- mlrun/serving/server.py +12 -22
- mlrun/serving/states.py +30 -162
- mlrun/serving/v2_serving.py +10 -13
- mlrun/utils/clones.py +1 -1
- mlrun/utils/model_monitoring.py +96 -122
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/METADATA +27 -23
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/RECORD +79 -92
- mlrun/api/crud/model_monitoring/grafana.py +0 -427
- mlrun/datastore/spark_udf.py +0 -40
- mlrun/model_monitoring/__init__.py +0 -44
- mlrun/model_monitoring/common.py +0 -112
- mlrun/model_monitoring/model_endpoint.py +0 -141
- mlrun/model_monitoring/stores/__init__.py +0 -106
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -448
- mlrun/model_monitoring/stores/model_endpoint_store.py +0 -147
- mlrun/model_monitoring/stores/models/__init__.py +0 -23
- mlrun/model_monitoring/stores/models/base.py +0 -18
- mlrun/model_monitoring/stores/models/mysql.py +0 -100
- mlrun/model_monitoring/stores/models/sqlite.py +0 -98
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -375
- mlrun/utils/db.py +0 -52
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/LICENSE +0 -0
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/WHEEL +0 -0
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/entry_points.txt +0 -0
- {mlrun-1.3.2rc1.dist-info → mlrun-1.3.2rc2.dist-info}/top_level.txt +0 -0
|
@@ -1,427 +0,0 @@
|
|
|
1
|
-
# Copyright 2018 Iguazio
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
from typing import Any, Dict, List, Optional, Set
|
|
17
|
-
|
|
18
|
-
import numpy as np
|
|
19
|
-
import pandas as pd
|
|
20
|
-
from fastapi.concurrency import run_in_threadpool
|
|
21
|
-
from sqlalchemy.orm import Session
|
|
22
|
-
|
|
23
|
-
import mlrun.api.crud
|
|
24
|
-
import mlrun.api.schemas
|
|
25
|
-
import mlrun.api.utils.auth.verifier
|
|
26
|
-
import mlrun.model_monitoring
|
|
27
|
-
from mlrun.api.schemas import (
|
|
28
|
-
GrafanaColumn,
|
|
29
|
-
GrafanaDataPoint,
|
|
30
|
-
GrafanaNumberColumn,
|
|
31
|
-
GrafanaTable,
|
|
32
|
-
GrafanaTimeSeriesTarget,
|
|
33
|
-
ProjectsFormat,
|
|
34
|
-
)
|
|
35
|
-
from mlrun.api.utils.singletons.project_member import get_project_member
|
|
36
|
-
from mlrun.errors import MLRunBadRequestError
|
|
37
|
-
from mlrun.utils import config, logger
|
|
38
|
-
from mlrun.utils.model_monitoring import parse_model_endpoint_store_prefix
|
|
39
|
-
from mlrun.utils.v3io_clients import get_frames_client
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def grafana_list_projects(
|
|
43
|
-
db_session: Session,
|
|
44
|
-
auth_info: mlrun.api.schemas.AuthInfo,
|
|
45
|
-
query_parameters: Dict[str, str],
|
|
46
|
-
) -> List[str]:
|
|
47
|
-
"""
|
|
48
|
-
List available project names. Will be used as a filter in each grafana dashboard.
|
|
49
|
-
|
|
50
|
-
:param db_session: A session that manages the current dialog with the database.
|
|
51
|
-
:param auth_info: The auth info of the request.
|
|
52
|
-
:param query_parameters: Dictionary of query parameters attached to the request. Note that this parameter is
|
|
53
|
-
required by the API even though it is not being used in this function.
|
|
54
|
-
|
|
55
|
-
:return: List of available project names.
|
|
56
|
-
"""
|
|
57
|
-
|
|
58
|
-
projects_output = get_project_member().list_projects(
|
|
59
|
-
db_session, format_=ProjectsFormat.name_only, leader_session=auth_info.session
|
|
60
|
-
)
|
|
61
|
-
return projects_output.projects
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
# TODO: remove in 1.5.0 the following functions: grafana_list_endpoints, grafana_individual_feature_analysis,
|
|
65
|
-
# grafana_overall_feature_analysis, grafana_income_features, parse_query_parameters, drop_grafana_escape_chars,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
async def grafana_list_endpoints(
|
|
69
|
-
body: Dict[str, Any],
|
|
70
|
-
query_parameters: Dict[str, str],
|
|
71
|
-
auth_info: mlrun.api.schemas.AuthInfo,
|
|
72
|
-
) -> List[GrafanaTable]:
|
|
73
|
-
project = query_parameters.get("project")
|
|
74
|
-
|
|
75
|
-
# Filters
|
|
76
|
-
model = query_parameters.get("model", None)
|
|
77
|
-
function = query_parameters.get("function", None)
|
|
78
|
-
labels = query_parameters.get("labels", "")
|
|
79
|
-
labels = labels.split(",") if labels else []
|
|
80
|
-
|
|
81
|
-
# Metrics to include
|
|
82
|
-
metrics = query_parameters.get("metrics", "")
|
|
83
|
-
metrics = metrics.split(",") if metrics else []
|
|
84
|
-
|
|
85
|
-
# Time range for metrics
|
|
86
|
-
start = body.get("rangeRaw", {}).get("start", "now-1h")
|
|
87
|
-
end = body.get("rangeRaw", {}).get("end", "now")
|
|
88
|
-
|
|
89
|
-
if project:
|
|
90
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_permissions(
|
|
91
|
-
project,
|
|
92
|
-
mlrun.api.schemas.AuthorizationAction.read,
|
|
93
|
-
auth_info,
|
|
94
|
-
)
|
|
95
|
-
endpoint_list = await run_in_threadpool(
|
|
96
|
-
mlrun.api.crud.ModelEndpoints().list_model_endpoints,
|
|
97
|
-
auth_info=auth_info,
|
|
98
|
-
project=project,
|
|
99
|
-
model=model,
|
|
100
|
-
function=function,
|
|
101
|
-
labels=labels,
|
|
102
|
-
metrics=metrics,
|
|
103
|
-
start=start,
|
|
104
|
-
end=end,
|
|
105
|
-
)
|
|
106
|
-
allowed_endpoints = await mlrun.api.utils.auth.verifier.AuthVerifier().filter_project_resources_by_permissions(
|
|
107
|
-
mlrun.api.schemas.AuthorizationResourceTypes.model_endpoint,
|
|
108
|
-
endpoint_list.endpoints,
|
|
109
|
-
lambda _endpoint: (
|
|
110
|
-
_endpoint.metadata.project,
|
|
111
|
-
_endpoint.metadata.uid,
|
|
112
|
-
),
|
|
113
|
-
auth_info,
|
|
114
|
-
)
|
|
115
|
-
endpoint_list.endpoints = allowed_endpoints
|
|
116
|
-
|
|
117
|
-
columns = [
|
|
118
|
-
GrafanaColumn(text="endpoint_id", type="string"),
|
|
119
|
-
GrafanaColumn(text="endpoint_function", type="string"),
|
|
120
|
-
GrafanaColumn(text="endpoint_model", type="string"),
|
|
121
|
-
GrafanaColumn(text="endpoint_model_class", type="string"),
|
|
122
|
-
GrafanaColumn(text="first_request", type="time"),
|
|
123
|
-
GrafanaColumn(text="last_request", type="time"),
|
|
124
|
-
GrafanaColumn(text="accuracy", type="number"),
|
|
125
|
-
GrafanaColumn(text="error_count", type="number"),
|
|
126
|
-
GrafanaColumn(text="drift_status", type="number"),
|
|
127
|
-
GrafanaColumn(text="predictions_per_second", type="number"),
|
|
128
|
-
GrafanaColumn(text="latency_avg_1h", type="number"),
|
|
129
|
-
]
|
|
130
|
-
|
|
131
|
-
table = GrafanaTable(columns=columns)
|
|
132
|
-
for endpoint in endpoint_list.endpoints:
|
|
133
|
-
row = [
|
|
134
|
-
endpoint.metadata.uid,
|
|
135
|
-
endpoint.spec.function_uri,
|
|
136
|
-
endpoint.spec.model,
|
|
137
|
-
endpoint.spec.model_class,
|
|
138
|
-
endpoint.status.first_request,
|
|
139
|
-
endpoint.status.last_request,
|
|
140
|
-
"N/A", # Leaving here for backwards compatibility
|
|
141
|
-
endpoint.status.error_count,
|
|
142
|
-
endpoint.status.drift_status,
|
|
143
|
-
]
|
|
144
|
-
|
|
145
|
-
if (
|
|
146
|
-
endpoint.status.metrics
|
|
147
|
-
and mlrun.model_monitoring.EventKeyMetrics.GENERIC
|
|
148
|
-
in endpoint.status.metrics
|
|
149
|
-
):
|
|
150
|
-
row.extend(
|
|
151
|
-
[
|
|
152
|
-
endpoint.status.metrics[
|
|
153
|
-
mlrun.model_monitoring.EventKeyMetrics.GENERIC
|
|
154
|
-
][mlrun.model_monitoring.EventLiveStats.PREDICTIONS_PER_SECOND],
|
|
155
|
-
endpoint.status.metrics[
|
|
156
|
-
mlrun.model_monitoring.EventKeyMetrics.GENERIC
|
|
157
|
-
][mlrun.model_monitoring.EventLiveStats.LATENCY_AVG_1H],
|
|
158
|
-
]
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
table.add_row(*row)
|
|
162
|
-
|
|
163
|
-
return [table]
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
async def grafana_individual_feature_analysis(
|
|
167
|
-
body: Dict[str, Any],
|
|
168
|
-
query_parameters: Dict[str, str],
|
|
169
|
-
auth_info: mlrun.api.schemas.AuthInfo,
|
|
170
|
-
):
|
|
171
|
-
endpoint_id = query_parameters.get("endpoint_id")
|
|
172
|
-
project = query_parameters.get("project")
|
|
173
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
|
|
174
|
-
mlrun.api.schemas.AuthorizationResourceTypes.model_endpoint,
|
|
175
|
-
project,
|
|
176
|
-
endpoint_id,
|
|
177
|
-
mlrun.api.schemas.AuthorizationAction.read,
|
|
178
|
-
auth_info,
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
endpoint = await run_in_threadpool(
|
|
182
|
-
mlrun.api.crud.ModelEndpoints().get_model_endpoint,
|
|
183
|
-
auth_info=auth_info,
|
|
184
|
-
project=project,
|
|
185
|
-
endpoint_id=endpoint_id,
|
|
186
|
-
feature_analysis=True,
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
# Load JSON data from KV, make sure not to fail if a field is missing
|
|
190
|
-
feature_stats = endpoint.status.feature_stats or {}
|
|
191
|
-
current_stats = endpoint.status.current_stats or {}
|
|
192
|
-
drift_measures = endpoint.status.drift_measures or {}
|
|
193
|
-
|
|
194
|
-
table = GrafanaTable(
|
|
195
|
-
columns=[
|
|
196
|
-
GrafanaColumn(text="feature_name", type="string"),
|
|
197
|
-
GrafanaColumn(text="actual_min", type="number"),
|
|
198
|
-
GrafanaColumn(text="actual_mean", type="number"),
|
|
199
|
-
GrafanaColumn(text="actual_max", type="number"),
|
|
200
|
-
GrafanaColumn(text="expected_min", type="number"),
|
|
201
|
-
GrafanaColumn(text="expected_mean", type="number"),
|
|
202
|
-
GrafanaColumn(text="expected_max", type="number"),
|
|
203
|
-
GrafanaColumn(text="tvd", type="number"),
|
|
204
|
-
GrafanaColumn(text="hellinger", type="number"),
|
|
205
|
-
GrafanaColumn(text="kld", type="number"),
|
|
206
|
-
]
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
for feature, base_stat in feature_stats.items():
|
|
210
|
-
current_stat = current_stats.get(feature, {})
|
|
211
|
-
drift_measure = drift_measures.get(feature, {})
|
|
212
|
-
|
|
213
|
-
table.add_row(
|
|
214
|
-
feature,
|
|
215
|
-
current_stat.get("min"),
|
|
216
|
-
current_stat.get("mean"),
|
|
217
|
-
current_stat.get("max"),
|
|
218
|
-
base_stat.get("min"),
|
|
219
|
-
base_stat.get("mean"),
|
|
220
|
-
base_stat.get("max"),
|
|
221
|
-
drift_measure.get("tvd"),
|
|
222
|
-
drift_measure.get("hellinger"),
|
|
223
|
-
drift_measure.get("kld"),
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
return [table]
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
async def grafana_overall_feature_analysis(
|
|
230
|
-
body: Dict[str, Any],
|
|
231
|
-
query_parameters: Dict[str, str],
|
|
232
|
-
auth_info: mlrun.api.schemas.AuthInfo,
|
|
233
|
-
):
|
|
234
|
-
endpoint_id = query_parameters.get("endpoint_id")
|
|
235
|
-
project = query_parameters.get("project")
|
|
236
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
|
|
237
|
-
mlrun.api.schemas.AuthorizationResourceTypes.model_endpoint,
|
|
238
|
-
project,
|
|
239
|
-
endpoint_id,
|
|
240
|
-
mlrun.api.schemas.AuthorizationAction.read,
|
|
241
|
-
auth_info,
|
|
242
|
-
)
|
|
243
|
-
endpoint = await run_in_threadpool(
|
|
244
|
-
mlrun.api.crud.ModelEndpoints().get_model_endpoint,
|
|
245
|
-
auth_info=auth_info,
|
|
246
|
-
project=project,
|
|
247
|
-
endpoint_id=endpoint_id,
|
|
248
|
-
feature_analysis=True,
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
table = GrafanaTable(
|
|
252
|
-
columns=[
|
|
253
|
-
GrafanaNumberColumn(text="tvd_sum"),
|
|
254
|
-
GrafanaNumberColumn(text="tvd_mean"),
|
|
255
|
-
GrafanaNumberColumn(text="hellinger_sum"),
|
|
256
|
-
GrafanaNumberColumn(text="hellinger_mean"),
|
|
257
|
-
GrafanaNumberColumn(text="kld_sum"),
|
|
258
|
-
GrafanaNumberColumn(text="kld_mean"),
|
|
259
|
-
]
|
|
260
|
-
)
|
|
261
|
-
|
|
262
|
-
if endpoint.status.drift_measures:
|
|
263
|
-
table.add_row(
|
|
264
|
-
endpoint.status.drift_measures.get("tvd_sum"),
|
|
265
|
-
endpoint.status.drift_measures.get("tvd_mean"),
|
|
266
|
-
endpoint.status.drift_measures.get("hellinger_sum"),
|
|
267
|
-
endpoint.status.drift_measures.get("hellinger_mean"),
|
|
268
|
-
endpoint.status.drift_measures.get("kld_sum"),
|
|
269
|
-
endpoint.status.drift_measures.get("kld_mean"),
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
return [table]
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
async def grafana_incoming_features(
|
|
276
|
-
body: Dict[str, Any],
|
|
277
|
-
query_parameters: Dict[str, str],
|
|
278
|
-
auth_info: mlrun.api.schemas.AuthInfo,
|
|
279
|
-
):
|
|
280
|
-
endpoint_id = query_parameters.get("endpoint_id")
|
|
281
|
-
project = query_parameters.get("project")
|
|
282
|
-
start = body.get("rangeRaw", {}).get("from", "now-1h")
|
|
283
|
-
end = body.get("rangeRaw", {}).get("to", "now")
|
|
284
|
-
|
|
285
|
-
await mlrun.api.utils.auth.verifier.AuthVerifier().query_project_resource_permissions(
|
|
286
|
-
mlrun.api.schemas.AuthorizationResourceTypes.model_endpoint,
|
|
287
|
-
project,
|
|
288
|
-
endpoint_id,
|
|
289
|
-
mlrun.api.schemas.AuthorizationAction.read,
|
|
290
|
-
auth_info,
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
endpoint = await run_in_threadpool(
|
|
294
|
-
mlrun.api.crud.ModelEndpoints().get_model_endpoint,
|
|
295
|
-
auth_info=auth_info,
|
|
296
|
-
project=project,
|
|
297
|
-
endpoint_id=endpoint_id,
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
time_series = []
|
|
301
|
-
|
|
302
|
-
feature_names = endpoint.spec.feature_names
|
|
303
|
-
|
|
304
|
-
if not feature_names:
|
|
305
|
-
logger.warn(
|
|
306
|
-
"'feature_names' is either missing or not initialized in endpoint record",
|
|
307
|
-
endpoint_id=endpoint.metadata.uid,
|
|
308
|
-
)
|
|
309
|
-
return time_series
|
|
310
|
-
|
|
311
|
-
path = config.model_endpoint_monitoring.store_prefixes.default.format(
|
|
312
|
-
project=project, kind=mlrun.api.schemas.ModelMonitoringStoreKinds.EVENTS
|
|
313
|
-
)
|
|
314
|
-
_, container, path = parse_model_endpoint_store_prefix(path)
|
|
315
|
-
|
|
316
|
-
client = get_frames_client(
|
|
317
|
-
token=auth_info.data_session,
|
|
318
|
-
address=config.v3io_framesd,
|
|
319
|
-
container=container,
|
|
320
|
-
)
|
|
321
|
-
|
|
322
|
-
data: pd.DataFrame = await run_in_threadpool(
|
|
323
|
-
client.read,
|
|
324
|
-
backend="tsdb",
|
|
325
|
-
table=path,
|
|
326
|
-
columns=feature_names,
|
|
327
|
-
filter=f"endpoint_id=='{endpoint_id}'",
|
|
328
|
-
start=start,
|
|
329
|
-
end=end,
|
|
330
|
-
)
|
|
331
|
-
|
|
332
|
-
data.drop(["endpoint_id"], axis=1, inplace=True, errors="ignore")
|
|
333
|
-
data.index = data.index.astype(np.int64) // 10**6
|
|
334
|
-
|
|
335
|
-
for feature, indexed_values in data.to_dict().items():
|
|
336
|
-
target = GrafanaTimeSeriesTarget(target=feature)
|
|
337
|
-
for index, value in indexed_values.items():
|
|
338
|
-
data_point = GrafanaDataPoint(value=float(value), timestamp=index)
|
|
339
|
-
target.add_data_point(data_point)
|
|
340
|
-
time_series.append(target)
|
|
341
|
-
|
|
342
|
-
return time_series
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
def parse_query_parameters(request_body: Dict[str, Any]) -> Dict[str, str]:
|
|
346
|
-
"""
|
|
347
|
-
This function searches for the target field in Grafana's SimpleJson json. Once located, the target string is
|
|
348
|
-
parsed by splitting on semi-colons (;). Each part in the resulting list is then split by an equal sign (=) to be
|
|
349
|
-
read as key-value pairs.
|
|
350
|
-
"""
|
|
351
|
-
|
|
352
|
-
# Try to get the target
|
|
353
|
-
targets = request_body.get("targets", [])
|
|
354
|
-
|
|
355
|
-
if len(targets) > 1:
|
|
356
|
-
logger.warn(
|
|
357
|
-
f"The 'targets' list contains more then one element ({len(targets)}), all targets except the first one are "
|
|
358
|
-
f"ignored."
|
|
359
|
-
)
|
|
360
|
-
|
|
361
|
-
target_obj = targets[0] if targets else {}
|
|
362
|
-
target_query = target_obj.get("target") if target_obj else ""
|
|
363
|
-
|
|
364
|
-
if not target_query:
|
|
365
|
-
raise MLRunBadRequestError(f"Target missing in request body:\n {request_body}")
|
|
366
|
-
|
|
367
|
-
parameters = _parse_parameters(target_query)
|
|
368
|
-
|
|
369
|
-
return parameters
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
def parse_search_parameters(request_body: Dict[str, Any]) -> Dict[str, str]:
|
|
373
|
-
"""
|
|
374
|
-
This function searches for the target field in Grafana's SimpleJson json. Once located, the target string is
|
|
375
|
-
parsed by splitting on semi-colons (;). Each part in the resulting list is then split by an equal sign (=) to be
|
|
376
|
-
read as key-value pairs.
|
|
377
|
-
"""
|
|
378
|
-
|
|
379
|
-
# Try to get the target
|
|
380
|
-
target = request_body.get("target")
|
|
381
|
-
|
|
382
|
-
if not target:
|
|
383
|
-
raise MLRunBadRequestError(f"Target missing in request body:\n {request_body}")
|
|
384
|
-
|
|
385
|
-
parameters = _parse_parameters(target)
|
|
386
|
-
|
|
387
|
-
return parameters
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
def _parse_parameters(target_query):
|
|
391
|
-
parameters = {}
|
|
392
|
-
for query in filter(lambda q: q, target_query.split(";")):
|
|
393
|
-
query_parts = query.split("=")
|
|
394
|
-
if len(query_parts) < 2:
|
|
395
|
-
raise MLRunBadRequestError(
|
|
396
|
-
f"Query must contain both query key and query value. Expected query_key=query_value, found {query} "
|
|
397
|
-
f"instead."
|
|
398
|
-
)
|
|
399
|
-
parameters[query_parts[0]] = query_parts[1]
|
|
400
|
-
return parameters
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
def drop_grafana_escape_chars(query_parameters: Dict[str, str]):
|
|
404
|
-
query_parameters = dict(query_parameters)
|
|
405
|
-
endpoint_id = query_parameters.get("endpoint_id")
|
|
406
|
-
if endpoint_id is not None:
|
|
407
|
-
query_parameters["endpoint_id"] = endpoint_id.replace("\\", "")
|
|
408
|
-
return query_parameters
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
def validate_query_parameters(
|
|
412
|
-
query_parameters: Dict[str, str], supported_endpoints: Optional[Set[str]] = None
|
|
413
|
-
):
|
|
414
|
-
"""Validates the parameters sent via Grafana's SimpleJson query"""
|
|
415
|
-
if "target_endpoint" not in query_parameters:
|
|
416
|
-
raise MLRunBadRequestError(
|
|
417
|
-
f"Expected 'target_endpoint' field in query, found {query_parameters} instead"
|
|
418
|
-
)
|
|
419
|
-
|
|
420
|
-
if (
|
|
421
|
-
supported_endpoints is not None
|
|
422
|
-
and query_parameters["target_endpoint"] not in supported_endpoints
|
|
423
|
-
):
|
|
424
|
-
raise MLRunBadRequestError(
|
|
425
|
-
f"{query_parameters['target_endpoint']} unsupported in query parameters: {query_parameters}. "
|
|
426
|
-
f"Currently supports: {','.join(supported_endpoints)}"
|
|
427
|
-
)
|
mlrun/datastore/spark_udf.py
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Copyright 2023 Iguazio
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
import hashlib
|
|
15
|
-
|
|
16
|
-
from pyspark.sql.functions import udf
|
|
17
|
-
from pyspark.sql.types import StringType
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _hash_list(*list_to_hash):
|
|
21
|
-
list_to_hash = [str(element) for element in list_to_hash]
|
|
22
|
-
str_concatted = "".join(list_to_hash)
|
|
23
|
-
sha1 = hashlib.sha1()
|
|
24
|
-
sha1.update(str_concatted.encode("utf8"))
|
|
25
|
-
return sha1.hexdigest()
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def _redis_stringify_key(key_list):
|
|
29
|
-
suffix = "}:static"
|
|
30
|
-
if isinstance(key_list, list):
|
|
31
|
-
if len(key_list) >= 2:
|
|
32
|
-
return str(key_list[0]) + "." + _hash_list(key_list[1:]) + suffix
|
|
33
|
-
if len(key_list) == 2:
|
|
34
|
-
return str(key_list[0]) + "." + str(key_list[1]) + suffix
|
|
35
|
-
return str(key_list[0]) + suffix
|
|
36
|
-
return str(key_list) + suffix
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
hash_and_concat_v3io_udf = udf(_hash_list, StringType())
|
|
40
|
-
hash_and_concat_redis_udf = udf(_redis_stringify_key, StringType())
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# Copyright 2018 Iguazio
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
#
|
|
15
|
-
# flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
|
|
16
|
-
# for backwards compatibility
|
|
17
|
-
|
|
18
|
-
__all__ = [
|
|
19
|
-
"ModelEndpoint",
|
|
20
|
-
"ModelMonitoringMode",
|
|
21
|
-
"EndpointType",
|
|
22
|
-
"create_model_endpoint_uid",
|
|
23
|
-
"EventFieldType",
|
|
24
|
-
"EventLiveStats",
|
|
25
|
-
"EventKeyMetrics",
|
|
26
|
-
"TimeSeriesTarget",
|
|
27
|
-
"ModelEndpointTarget",
|
|
28
|
-
"FileTargetKind",
|
|
29
|
-
"ProjectSecretKeys",
|
|
30
|
-
"ModelMonitoringStoreKinds",
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
from .common import EndpointType, ModelMonitoringMode, create_model_endpoint_uid
|
|
34
|
-
from .constants import (
|
|
35
|
-
EventFieldType,
|
|
36
|
-
EventKeyMetrics,
|
|
37
|
-
EventLiveStats,
|
|
38
|
-
FileTargetKind,
|
|
39
|
-
ModelEndpointTarget,
|
|
40
|
-
ModelMonitoringStoreKinds,
|
|
41
|
-
ProjectSecretKeys,
|
|
42
|
-
TimeSeriesTarget,
|
|
43
|
-
)
|
|
44
|
-
from .model_endpoint import ModelEndpoint
|
mlrun/model_monitoring/common.py
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# Copyright 2018 Iguazio
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
import enum
|
|
17
|
-
import hashlib
|
|
18
|
-
from dataclasses import dataclass
|
|
19
|
-
from typing import Optional
|
|
20
|
-
|
|
21
|
-
import mlrun.utils
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class ModelMonitoringMode(str, enum.Enum):
|
|
25
|
-
enabled = "enabled"
|
|
26
|
-
disabled = "disabled"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class EndpointType(enum.IntEnum):
|
|
30
|
-
NODE_EP = 1 # end point that is not a child of a router
|
|
31
|
-
ROUTER = 2 # endpoint that is router
|
|
32
|
-
LEAF_EP = 3 # end point that is a child of a router
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def create_model_endpoint_uid(function_uri: str, versioned_model: str):
|
|
36
|
-
function_uri = FunctionURI.from_string(function_uri)
|
|
37
|
-
versioned_model = VersionedModel.from_string(versioned_model)
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
not function_uri.project
|
|
41
|
-
or not function_uri.function
|
|
42
|
-
or not versioned_model.model
|
|
43
|
-
):
|
|
44
|
-
raise ValueError("Both function_uri and versioned_model have to be initialized")
|
|
45
|
-
|
|
46
|
-
uid = EndpointUID(
|
|
47
|
-
function_uri.project,
|
|
48
|
-
function_uri.function,
|
|
49
|
-
function_uri.tag,
|
|
50
|
-
function_uri.hash_key,
|
|
51
|
-
versioned_model.model,
|
|
52
|
-
versioned_model.version,
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
return uid
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@dataclass
|
|
59
|
-
class FunctionURI:
|
|
60
|
-
project: str
|
|
61
|
-
function: str
|
|
62
|
-
tag: Optional[str] = None
|
|
63
|
-
hash_key: Optional[str] = None
|
|
64
|
-
|
|
65
|
-
@classmethod
|
|
66
|
-
def from_string(cls, function_uri):
|
|
67
|
-
project, uri, tag, hash_key = mlrun.utils.parse_versioned_object_uri(
|
|
68
|
-
function_uri
|
|
69
|
-
)
|
|
70
|
-
return cls(
|
|
71
|
-
project=project,
|
|
72
|
-
function=uri,
|
|
73
|
-
tag=tag or None,
|
|
74
|
-
hash_key=hash_key or None,
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
@dataclass
|
|
79
|
-
class VersionedModel:
|
|
80
|
-
model: str
|
|
81
|
-
version: Optional[str]
|
|
82
|
-
|
|
83
|
-
@classmethod
|
|
84
|
-
def from_string(cls, model):
|
|
85
|
-
try:
|
|
86
|
-
model, version = model.split(":")
|
|
87
|
-
except ValueError:
|
|
88
|
-
model, version = model, None
|
|
89
|
-
|
|
90
|
-
return cls(model, version)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@dataclass
|
|
94
|
-
class EndpointUID:
|
|
95
|
-
project: str
|
|
96
|
-
function: str
|
|
97
|
-
function_tag: str
|
|
98
|
-
function_hash_key: str
|
|
99
|
-
model: str
|
|
100
|
-
model_version: str
|
|
101
|
-
uid: Optional[str] = None
|
|
102
|
-
|
|
103
|
-
def __post_init__(self):
|
|
104
|
-
function_ref = (
|
|
105
|
-
f"{self.function}_{self.function_tag or self.function_hash_key or 'N/A'}"
|
|
106
|
-
)
|
|
107
|
-
versioned_model = f"{self.model}_{self.model_version or 'N/A'}"
|
|
108
|
-
unique_string = f"{self.project}_{function_ref}_{versioned_model}"
|
|
109
|
-
self.uid = hashlib.sha1(unique_string.encode("utf-8")).hexdigest()
|
|
110
|
-
|
|
111
|
-
def __str__(self):
|
|
112
|
-
return self.uid
|