mlrun 1.5.0rc1__py3-none-any.whl → 1.5.0rc2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +2 -35
- mlrun/__main__.py +1 -40
- mlrun/api/api/api.py +6 -0
- mlrun/api/api/endpoints/feature_store.py +0 -4
- mlrun/api/api/endpoints/files.py +14 -2
- mlrun/api/api/endpoints/functions.py +6 -1
- mlrun/api/api/endpoints/logs.py +17 -3
- mlrun/api/api/endpoints/pipelines.py +1 -5
- mlrun/api/api/endpoints/projects.py +88 -0
- mlrun/api/api/endpoints/runs.py +48 -6
- mlrun/api/api/endpoints/workflows.py +355 -0
- mlrun/api/api/utils.py +1 -1
- mlrun/api/crud/__init__.py +1 -0
- mlrun/api/crud/client_spec.py +3 -0
- mlrun/api/crud/model_monitoring/deployment.py +36 -7
- mlrun/api/crud/model_monitoring/grafana.py +1 -1
- mlrun/api/crud/model_monitoring/helpers.py +32 -2
- mlrun/api/crud/model_monitoring/model_endpoints.py +27 -5
- mlrun/api/crud/notifications.py +9 -4
- mlrun/api/crud/pipelines.py +4 -9
- mlrun/api/crud/runtime_resources.py +4 -3
- mlrun/api/crud/secrets.py +21 -0
- mlrun/api/crud/workflows.py +352 -0
- mlrun/api/db/base.py +16 -1
- mlrun/api/db/sqldb/db.py +97 -16
- mlrun/api/launcher.py +26 -7
- mlrun/api/main.py +3 -4
- mlrun/{mlutils → api/rundb}/__init__.py +2 -6
- mlrun/{db → api/rundb}/sqldb.py +35 -83
- mlrun/api/runtime_handlers/__init__.py +56 -0
- mlrun/api/runtime_handlers/base.py +1247 -0
- mlrun/api/runtime_handlers/daskjob.py +209 -0
- mlrun/api/runtime_handlers/kubejob.py +37 -0
- mlrun/api/runtime_handlers/mpijob.py +147 -0
- mlrun/api/runtime_handlers/remotesparkjob.py +29 -0
- mlrun/api/runtime_handlers/sparkjob.py +148 -0
- mlrun/api/utils/builder.py +1 -4
- mlrun/api/utils/clients/chief.py +14 -0
- mlrun/api/utils/scheduler.py +98 -15
- mlrun/api/utils/singletons/db.py +4 -0
- mlrun/artifacts/manager.py +1 -2
- mlrun/common/schemas/__init__.py +6 -0
- mlrun/common/schemas/auth.py +4 -1
- mlrun/common/schemas/client_spec.py +1 -1
- mlrun/common/schemas/model_monitoring/__init__.py +1 -0
- mlrun/common/schemas/model_monitoring/constants.py +11 -0
- mlrun/common/schemas/project.py +1 -0
- mlrun/common/schemas/runs.py +1 -8
- mlrun/common/schemas/schedule.py +1 -8
- mlrun/common/schemas/workflow.py +54 -0
- mlrun/config.py +42 -40
- mlrun/datastore/sources.py +1 -1
- mlrun/db/__init__.py +4 -68
- mlrun/db/base.py +12 -0
- mlrun/db/factory.py +65 -0
- mlrun/db/httpdb.py +175 -19
- mlrun/db/nopdb.py +4 -2
- mlrun/execution.py +4 -2
- mlrun/feature_store/__init__.py +1 -0
- mlrun/feature_store/api.py +1 -2
- mlrun/feature_store/feature_set.py +0 -10
- mlrun/feature_store/feature_vector.py +340 -2
- mlrun/feature_store/ingestion.py +5 -10
- mlrun/feature_store/retrieval/base.py +118 -104
- mlrun/feature_store/retrieval/dask_merger.py +17 -10
- mlrun/feature_store/retrieval/job.py +4 -1
- mlrun/feature_store/retrieval/local_merger.py +18 -18
- mlrun/feature_store/retrieval/spark_merger.py +21 -14
- mlrun/feature_store/retrieval/storey_merger.py +21 -15
- mlrun/kfpops.py +3 -9
- mlrun/launcher/base.py +3 -3
- mlrun/launcher/client.py +3 -2
- mlrun/launcher/factory.py +16 -13
- mlrun/lists.py +0 -11
- mlrun/model.py +9 -15
- mlrun/model_monitoring/helpers.py +15 -25
- mlrun/model_monitoring/model_monitoring_batch.py +72 -4
- mlrun/model_monitoring/prometheus.py +219 -0
- mlrun/model_monitoring/stores/__init__.py +15 -9
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +3 -1
- mlrun/model_monitoring/stream_processing.py +181 -29
- mlrun/package/packager.py +6 -8
- mlrun/package/packagers/default_packager.py +121 -10
- mlrun/platforms/__init__.py +0 -2
- mlrun/platforms/iguazio.py +0 -56
- mlrun/projects/pipelines.py +57 -158
- mlrun/projects/project.py +6 -32
- mlrun/render.py +1 -1
- mlrun/run.py +2 -124
- mlrun/runtimes/__init__.py +6 -42
- mlrun/runtimes/base.py +26 -1241
- mlrun/runtimes/daskjob.py +2 -198
- mlrun/runtimes/function.py +16 -5
- mlrun/runtimes/kubejob.py +5 -29
- mlrun/runtimes/mpijob/__init__.py +2 -2
- mlrun/runtimes/mpijob/abstract.py +10 -1
- mlrun/runtimes/mpijob/v1.py +0 -76
- mlrun/runtimes/mpijob/v1alpha1.py +1 -74
- mlrun/runtimes/nuclio.py +3 -2
- mlrun/runtimes/pod.py +0 -10
- mlrun/runtimes/remotesparkjob.py +1 -15
- mlrun/runtimes/serving.py +1 -1
- mlrun/runtimes/sparkjob/__init__.py +0 -1
- mlrun/runtimes/sparkjob/abstract.py +4 -131
- mlrun/serving/states.py +1 -1
- mlrun/utils/db.py +0 -2
- mlrun/utils/helpers.py +19 -13
- mlrun/utils/notifications/notification_pusher.py +5 -25
- mlrun/utils/regex.py +7 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.5.0rc1.dist-info → mlrun-1.5.0rc2.dist-info}/METADATA +24 -23
- {mlrun-1.5.0rc1.dist-info → mlrun-1.5.0rc2.dist-info}/RECORD +116 -107
- {mlrun-1.5.0rc1.dist-info → mlrun-1.5.0rc2.dist-info}/WHEEL +1 -1
- mlrun/mlutils/data.py +0 -160
- mlrun/mlutils/models.py +0 -78
- mlrun/mlutils/plots.py +0 -902
- {mlrun-1.5.0rc1.dist-info → mlrun-1.5.0rc2.dist-info}/LICENSE +0 -0
- {mlrun-1.5.0rc1.dist-info → mlrun-1.5.0rc2.dist-info}/entry_points.txt +0 -0
- {mlrun-1.5.0rc1.dist-info → mlrun-1.5.0rc2.dist-info}/top_level.txt +0 -0
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import collections
|
|
15
15
|
import logging
|
|
16
|
+
import typing
|
|
16
17
|
from copy import copy
|
|
17
18
|
from enum import Enum
|
|
18
19
|
from typing import List, Union
|
|
@@ -30,8 +31,16 @@ from ..feature_store.common import (
|
|
|
30
31
|
parse_feature_string,
|
|
31
32
|
parse_project_name_from_feature_string,
|
|
32
33
|
)
|
|
33
|
-
from ..
|
|
34
|
-
from ..
|
|
34
|
+
from ..feature_store.feature_set import FeatureSet
|
|
35
|
+
from ..features import Entity, Feature
|
|
36
|
+
from ..model import (
|
|
37
|
+
DataSource,
|
|
38
|
+
DataTarget,
|
|
39
|
+
ModelObj,
|
|
40
|
+
ObjectDict,
|
|
41
|
+
ObjectList,
|
|
42
|
+
VersionedObjMetadata,
|
|
43
|
+
)
|
|
35
44
|
from ..runtimes.function_reference import FunctionReference
|
|
36
45
|
from ..serving.states import RootFlowStep
|
|
37
46
|
from ..utils import StorePrefix
|
|
@@ -50,17 +59,25 @@ class FeatureVectorSpec(ModelObj):
|
|
|
50
59
|
with_indexes=None,
|
|
51
60
|
function=None,
|
|
52
61
|
analysis=None,
|
|
62
|
+
relations=None,
|
|
63
|
+
join_graph=None,
|
|
53
64
|
):
|
|
54
65
|
self._graph: RootFlowStep = None
|
|
55
66
|
self._entity_fields: ObjectList = None
|
|
56
67
|
self._entity_source: DataSource = None
|
|
57
68
|
self._function: FunctionReference = None
|
|
69
|
+
self._relations: typing.Dict[str, ObjectDict] = None
|
|
70
|
+
self._join_graph: JoinGraph = None
|
|
58
71
|
|
|
59
72
|
self.description = description
|
|
60
73
|
self.features: List[str] = features or []
|
|
61
74
|
self.entity_source = entity_source
|
|
62
75
|
self.entity_fields = entity_fields or []
|
|
63
76
|
self.graph = graph
|
|
77
|
+
self.join_graph = join_graph
|
|
78
|
+
self.relations: typing.Dict[str, typing.Dict[str, Union[Entity, str]]] = (
|
|
79
|
+
relations or {}
|
|
80
|
+
)
|
|
64
81
|
self.timestamp_field = timestamp_field
|
|
65
82
|
self.label_feature = label_feature
|
|
66
83
|
self.with_indexes = with_indexes
|
|
@@ -104,6 +121,38 @@ class FeatureVectorSpec(ModelObj):
|
|
|
104
121
|
def function(self, function):
|
|
105
122
|
self._function = self._verify_dict(function, "function", FunctionReference)
|
|
106
123
|
|
|
124
|
+
@property
|
|
125
|
+
def relations(self) -> typing.Dict[str, ObjectDict]:
|
|
126
|
+
"""feature set relations dict"""
|
|
127
|
+
return self._relations
|
|
128
|
+
|
|
129
|
+
@relations.setter
|
|
130
|
+
def relations(
|
|
131
|
+
self, relations: typing.Dict[str, typing.Dict[str, Union[Entity, str]]]
|
|
132
|
+
):
|
|
133
|
+
temp_relations = {}
|
|
134
|
+
for fs_name, relation in relations.items():
|
|
135
|
+
for col, ent in relation.items():
|
|
136
|
+
if isinstance(ent, str):
|
|
137
|
+
relation[col] = Entity(ent)
|
|
138
|
+
temp_relations[fs_name] = ObjectDict.from_dict(
|
|
139
|
+
{"entity": Entity}, relation, "entity"
|
|
140
|
+
)
|
|
141
|
+
self._relations = ObjectDict.from_dict(
|
|
142
|
+
{"object_dict": ObjectDict}, temp_relations, "object_dict"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def join_graph(self):
|
|
147
|
+
return self._join_graph
|
|
148
|
+
|
|
149
|
+
@join_graph.setter
|
|
150
|
+
def join_graph(self, join_graph):
|
|
151
|
+
if join_graph is not None:
|
|
152
|
+
self._join_graph = self._verify_dict(join_graph, "join_graph", JoinGraph)
|
|
153
|
+
else:
|
|
154
|
+
self._join_graph = None
|
|
155
|
+
|
|
107
156
|
|
|
108
157
|
class FeatureVectorStatus(ModelObj):
|
|
109
158
|
def __init__(
|
|
@@ -151,6 +200,267 @@ class FeatureVectorStatus(ModelObj):
|
|
|
151
200
|
self._features = ObjectList.from_list(Feature, features)
|
|
152
201
|
|
|
153
202
|
|
|
203
|
+
class JoinGraph(ModelObj):
|
|
204
|
+
"""
|
|
205
|
+
explain here about the class
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
default_graph_name = "$__join_graph_fv__$"
|
|
209
|
+
first_join_type = "first"
|
|
210
|
+
_dict_fields = ["name", "first_feature_set", "steps"]
|
|
211
|
+
|
|
212
|
+
def __init__(
|
|
213
|
+
self,
|
|
214
|
+
name: str = None,
|
|
215
|
+
first_feature_set: Union[str, FeatureSet] = None,
|
|
216
|
+
):
|
|
217
|
+
"""
|
|
218
|
+
JoinGraph is a class that represents a graph of data joins between feature sets. It allows users to define
|
|
219
|
+
data joins step by step, specifying the join type for each step. The graph can be used to build a sequence of
|
|
220
|
+
joins that will be executed in order, allowing the creation of complex join operations between feature sets.
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
Example:
|
|
224
|
+
# Create a new JoinGraph and add steps for joining feature sets.
|
|
225
|
+
join_graph = JoinGraph(name="my_join_graph", first_feature_set="featureset1")
|
|
226
|
+
join_graph.inner("featureset2")
|
|
227
|
+
join_graph.left("featureset3", asof_join=True)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
:param name: (str, optional) The name of the join graph. If not provided,
|
|
231
|
+
a default name will be used.
|
|
232
|
+
:param first_feature_set: (str or FeatureSet, optional) The first feature set to join. It can be
|
|
233
|
+
specified either as a string representing the name of the feature set or as a
|
|
234
|
+
FeatureSet object.
|
|
235
|
+
"""
|
|
236
|
+
self.name = name or self.default_graph_name
|
|
237
|
+
self._steps: ObjectList = None
|
|
238
|
+
self._feature_sets = None
|
|
239
|
+
if first_feature_set:
|
|
240
|
+
self._start(first_feature_set)
|
|
241
|
+
|
|
242
|
+
def inner(self, other_operand: typing.Union[str, FeatureSet]):
|
|
243
|
+
"""
|
|
244
|
+
Specifies an inner join with the given feature set
|
|
245
|
+
|
|
246
|
+
:param other_operand: (str or FeatureSet) The name of the feature set or a FeatureSet object to join with.
|
|
247
|
+
|
|
248
|
+
:return: JoinGraph: The updated JoinGraph object with the specified inner join.
|
|
249
|
+
"""
|
|
250
|
+
return self._join_operands(other_operand, "inner")
|
|
251
|
+
|
|
252
|
+
def outer(self, other_operand: typing.Union[str, FeatureSet]):
|
|
253
|
+
"""
|
|
254
|
+
Specifies an outer join with the given feature set
|
|
255
|
+
|
|
256
|
+
:param other_operand: (str or FeatureSet) The name of the feature set or a FeatureSet object to join with.
|
|
257
|
+
:return: JoinGraph: The updated JoinGraph object with the specified outer join.
|
|
258
|
+
"""
|
|
259
|
+
return self._join_operands(other_operand, "outer")
|
|
260
|
+
|
|
261
|
+
def left(self, other_operand: typing.Union[str, FeatureSet], asof_join):
|
|
262
|
+
"""
|
|
263
|
+
Specifies a left join with the given feature set
|
|
264
|
+
|
|
265
|
+
:param other_operand: (str or FeatureSet) The name of the feature set or a FeatureSet object to join with.
|
|
266
|
+
:param asof_join: (bool) A flag indicating whether to perform an as-of join.
|
|
267
|
+
|
|
268
|
+
:return: JoinGraph: The updated JoinGraph object with the specified left join.
|
|
269
|
+
"""
|
|
270
|
+
return self._join_operands(other_operand, "left", asof_join=asof_join)
|
|
271
|
+
|
|
272
|
+
def right(self, other_operand: typing.Union[str, FeatureSet]):
|
|
273
|
+
"""
|
|
274
|
+
Specifies a right join with the given feature set
|
|
275
|
+
|
|
276
|
+
:param other_operand: (str or FeatureSet) The name of the feature set or a FeatureSet object to join with.
|
|
277
|
+
|
|
278
|
+
:return: JoinGraph: The updated JoinGraph object with the specified right join.
|
|
279
|
+
"""
|
|
280
|
+
return self._join_operands(other_operand, "right")
|
|
281
|
+
|
|
282
|
+
def _join_operands(
|
|
283
|
+
self,
|
|
284
|
+
other_operand: typing.Union[str, FeatureSet],
|
|
285
|
+
join_type: str,
|
|
286
|
+
asof_join: bool = False,
|
|
287
|
+
):
|
|
288
|
+
if isinstance(other_operand, FeatureSet):
|
|
289
|
+
other_operand = other_operand.metadata.name
|
|
290
|
+
|
|
291
|
+
first_key_num = len(self._steps.keys()) if self._steps else 0
|
|
292
|
+
left_last_step_name, left_all_feature_sets = (
|
|
293
|
+
self.last_step_name,
|
|
294
|
+
self.all_feature_sets_names,
|
|
295
|
+
)
|
|
296
|
+
is_first_fs = (
|
|
297
|
+
join_type == JoinGraph.first_join_type or left_all_feature_sets == self.name
|
|
298
|
+
)
|
|
299
|
+
# create_new_step
|
|
300
|
+
new_step = _JoinStep(
|
|
301
|
+
f"step_{first_key_num}",
|
|
302
|
+
left_last_step_name if not is_first_fs else "",
|
|
303
|
+
other_operand,
|
|
304
|
+
left_all_feature_sets if not is_first_fs else [],
|
|
305
|
+
other_operand,
|
|
306
|
+
join_type,
|
|
307
|
+
asof_join,
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
if self.steps is not None:
|
|
311
|
+
self.steps.update(new_step)
|
|
312
|
+
else:
|
|
313
|
+
self.steps = [new_step]
|
|
314
|
+
return self
|
|
315
|
+
|
|
316
|
+
def _start(self, other_operand: typing.Union[str, FeatureSet]):
|
|
317
|
+
return self._join_operands(other_operand, JoinGraph.first_join_type)
|
|
318
|
+
|
|
319
|
+
def _init_all_join_keys(self, feature_set_objects, vector):
|
|
320
|
+
for step in self.steps:
|
|
321
|
+
step.init_join_keys(feature_set_objects, vector)
|
|
322
|
+
|
|
323
|
+
@property
|
|
324
|
+
def all_feature_sets_names(self):
|
|
325
|
+
"""
|
|
326
|
+
Returns a list of all feature set names included in the join graph.
|
|
327
|
+
|
|
328
|
+
:return: List[str]: A list of feature set names.
|
|
329
|
+
"""
|
|
330
|
+
if self._steps:
|
|
331
|
+
return self._steps[-1].left_feature_set_names + [
|
|
332
|
+
self._steps[-1].right_feature_set_name
|
|
333
|
+
]
|
|
334
|
+
else:
|
|
335
|
+
return self.name
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
def last_step_name(self):
|
|
339
|
+
"""
|
|
340
|
+
Returns the name of the last step in the join graph.
|
|
341
|
+
|
|
342
|
+
:return: str: The name of the last step.
|
|
343
|
+
"""
|
|
344
|
+
if self._steps:
|
|
345
|
+
return self._steps[-1].name
|
|
346
|
+
else:
|
|
347
|
+
return self.name
|
|
348
|
+
|
|
349
|
+
@property
|
|
350
|
+
def steps(self):
|
|
351
|
+
"""
|
|
352
|
+
Returns the list of join steps as ObjectList, which can be used to iterate over the steps
|
|
353
|
+
or access the properties of each step.
|
|
354
|
+
:return: ObjectList: The list of join steps.
|
|
355
|
+
"""
|
|
356
|
+
return self._steps
|
|
357
|
+
|
|
358
|
+
@steps.setter
|
|
359
|
+
def steps(self, steps):
|
|
360
|
+
"""
|
|
361
|
+
Setter for the steps property. It allows updating the join steps.
|
|
362
|
+
|
|
363
|
+
:param steps: (List[_JoinStep]) The list of join steps.
|
|
364
|
+
"""
|
|
365
|
+
self._steps = ObjectList.from_list(child_class=_JoinStep, children=steps)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
class _JoinStep(ModelObj):
|
|
369
|
+
def __init__(
|
|
370
|
+
self,
|
|
371
|
+
name: str = None,
|
|
372
|
+
left_step_name: str = None,
|
|
373
|
+
right_step_name: str = None,
|
|
374
|
+
left_feature_set_names: Union[str, List[str]] = None,
|
|
375
|
+
right_feature_set_name: str = None,
|
|
376
|
+
join_type: str = "inner",
|
|
377
|
+
asof_join: bool = False,
|
|
378
|
+
):
|
|
379
|
+
self.name = name
|
|
380
|
+
self.left_step_name = left_step_name
|
|
381
|
+
self.right_step_name = right_step_name
|
|
382
|
+
self.left_feature_set_names = (
|
|
383
|
+
left_feature_set_names
|
|
384
|
+
if isinstance(left_feature_set_names, list)
|
|
385
|
+
else [left_feature_set_names]
|
|
386
|
+
)
|
|
387
|
+
self.right_feature_set_name = right_feature_set_name
|
|
388
|
+
self.join_type = join_type
|
|
389
|
+
self.asof_join = asof_join
|
|
390
|
+
|
|
391
|
+
self.left_keys = []
|
|
392
|
+
self.right_keys = []
|
|
393
|
+
|
|
394
|
+
def init_join_keys(
|
|
395
|
+
self,
|
|
396
|
+
feature_set_objects: ObjectList,
|
|
397
|
+
vector,
|
|
398
|
+
):
|
|
399
|
+
self.left_keys = []
|
|
400
|
+
self.right_keys = []
|
|
401
|
+
|
|
402
|
+
if (
|
|
403
|
+
self.join_type == JoinGraph.first_join_type
|
|
404
|
+
or not self.left_feature_set_names
|
|
405
|
+
):
|
|
406
|
+
self.left_keys = self.right_keys = list(
|
|
407
|
+
feature_set_objects[self.right_feature_set_name].spec.entities.keys()
|
|
408
|
+
)
|
|
409
|
+
self.join_type = (
|
|
410
|
+
"inner"
|
|
411
|
+
if self.join_type == JoinGraph.first_join_type
|
|
412
|
+
else self.join_type
|
|
413
|
+
)
|
|
414
|
+
return
|
|
415
|
+
|
|
416
|
+
for left_fset in self.left_feature_set_names:
|
|
417
|
+
left_keys, right_keys = self._check_relation(
|
|
418
|
+
vector.get_feature_set_relations(feature_set_objects[left_fset]),
|
|
419
|
+
list(feature_set_objects[left_fset].spec.entities),
|
|
420
|
+
feature_set_objects[self.right_feature_set_name],
|
|
421
|
+
)
|
|
422
|
+
self.left_keys.extend(left_keys)
|
|
423
|
+
self.right_keys.extend(right_keys)
|
|
424
|
+
|
|
425
|
+
if not self.left_keys:
|
|
426
|
+
raise mlrun.errors.MLRunRuntimeError(
|
|
427
|
+
f"{self.name} can't be preform due to undefined relation between "
|
|
428
|
+
f"{self.left_feature_set_names} to {self.right_feature_set_name}"
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
@staticmethod
|
|
432
|
+
def _check_relation(
|
|
433
|
+
relation: typing.Dict[str, Union[str, Entity]],
|
|
434
|
+
entities: List[Entity],
|
|
435
|
+
right_fset_fields,
|
|
436
|
+
):
|
|
437
|
+
right_feature_set_entity_list = right_fset_fields.spec.entities
|
|
438
|
+
|
|
439
|
+
if all(ent in entities for ent in right_feature_set_entity_list) and len(
|
|
440
|
+
right_feature_set_entity_list
|
|
441
|
+
) == len(entities):
|
|
442
|
+
# entities wise
|
|
443
|
+
return list(right_feature_set_entity_list.keys()), list(
|
|
444
|
+
right_feature_set_entity_list.keys()
|
|
445
|
+
)
|
|
446
|
+
curr_col_relation_list = list(
|
|
447
|
+
map(
|
|
448
|
+
lambda ent: (
|
|
449
|
+
list(relation.keys())[list(relation.values()).index(ent)]
|
|
450
|
+
if ent in list(relation.values())
|
|
451
|
+
else False
|
|
452
|
+
),
|
|
453
|
+
right_feature_set_entity_list,
|
|
454
|
+
)
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
if all(curr_col_relation_list):
|
|
458
|
+
# relation wise
|
|
459
|
+
return curr_col_relation_list, list(right_feature_set_entity_list.keys())
|
|
460
|
+
|
|
461
|
+
return [], []
|
|
462
|
+
|
|
463
|
+
|
|
154
464
|
class FeatureVector(ModelObj):
|
|
155
465
|
"""Feature vector, specify selected features, their metadata and material views"""
|
|
156
466
|
|
|
@@ -164,6 +474,8 @@ class FeatureVector(ModelObj):
|
|
|
164
474
|
label_feature=None,
|
|
165
475
|
description=None,
|
|
166
476
|
with_indexes=None,
|
|
477
|
+
join_graph: JoinGraph = None,
|
|
478
|
+
relations: typing.Dict[str, typing.Dict[str, Union[Entity, str]]] = None,
|
|
167
479
|
):
|
|
168
480
|
"""Feature vector, specify selected features, their metadata and material views
|
|
169
481
|
|
|
@@ -186,6 +498,18 @@ class FeatureVector(ModelObj):
|
|
|
186
498
|
:param label_feature: feature name to be used as label data
|
|
187
499
|
:param description: text description of the vector
|
|
188
500
|
:param with_indexes: whether to keep the entity and timestamp columns in the response
|
|
501
|
+
:param join_graph: An optional JoinGraph object representing the graph of data joins
|
|
502
|
+
between feature sets for this feature vector, specified the order and the join types.
|
|
503
|
+
:param relations: {<feature_set name>: {<column_name>: <other entity object/name>, ...}...}
|
|
504
|
+
An optional dictionary specifying the relations between feature sets in the
|
|
505
|
+
feature vector. The keys of the dictionary are feature set names, and the values
|
|
506
|
+
are dictionaries where the keys represent column names(of the feature set),
|
|
507
|
+
and the values represent the target entities to join with.
|
|
508
|
+
The relations provided here will take precedence over the relations that were specified
|
|
509
|
+
on the feature sets themselves. In case a specific feature set is not mentioned as a key
|
|
510
|
+
here, the function will fall back to using the default relations defined in the
|
|
511
|
+
feature set.
|
|
512
|
+
|
|
189
513
|
"""
|
|
190
514
|
self._spec: FeatureVectorSpec = None
|
|
191
515
|
self._metadata = None
|
|
@@ -196,6 +520,8 @@ class FeatureVector(ModelObj):
|
|
|
196
520
|
features=features,
|
|
197
521
|
label_feature=label_feature,
|
|
198
522
|
with_indexes=with_indexes,
|
|
523
|
+
relations=relations,
|
|
524
|
+
join_graph=join_graph,
|
|
199
525
|
)
|
|
200
526
|
self.metadata = VersionedObjMetadata(name=name)
|
|
201
527
|
self.status = None
|
|
@@ -380,6 +706,18 @@ class FeatureVector(ModelObj):
|
|
|
380
706
|
self.status.index_keys = index_keys
|
|
381
707
|
return feature_set_objects, feature_set_fields
|
|
382
708
|
|
|
709
|
+
def get_feature_set_relations(self, feature_set: Union[str, FeatureSet]):
|
|
710
|
+
if isinstance(feature_set, str):
|
|
711
|
+
feature_set = get_feature_set_by_uri(
|
|
712
|
+
feature_set,
|
|
713
|
+
self.metadata.project,
|
|
714
|
+
)
|
|
715
|
+
name = feature_set.metadata.name
|
|
716
|
+
feature_set_relations = feature_set.spec.relations or {}
|
|
717
|
+
if self.spec.relations and name in self.spec.relations:
|
|
718
|
+
feature_set_relations = self.spec.relations[name]
|
|
719
|
+
return feature_set_relations
|
|
720
|
+
|
|
383
721
|
|
|
384
722
|
class OnlineVectorService:
|
|
385
723
|
"""get_online_feature_service response object"""
|
mlrun/feature_store/ingestion.py
CHANGED
|
@@ -278,17 +278,12 @@ def run_ingestion_job(name, featureset, run_config, schedule=None, spark_service
|
|
|
278
278
|
# when running in server side we want to set the function db connection to the actual DB and not to use the httpdb
|
|
279
279
|
function.set_db_connection(featureset._get_run_db())
|
|
280
280
|
|
|
281
|
-
# when running on server side there are multiple enrichments and validations to be applied on a function,
|
|
282
|
-
# auth_info is an attribute which is been added only on server side.
|
|
283
|
-
if run_config.auth_info:
|
|
284
|
-
# using from to not conflict with other mlrun imports
|
|
285
|
-
from mlrun.api.api.utils import apply_enrichment_and_validation_on_function
|
|
286
|
-
|
|
287
|
-
# apply_enrichment_and_validation_on_function is a server side function we don't want to import it on client
|
|
288
|
-
apply_enrichment_and_validation_on_function(function, run_config.auth_info)
|
|
289
|
-
|
|
290
281
|
run = function.run(
|
|
291
|
-
task,
|
|
282
|
+
task,
|
|
283
|
+
schedule=schedule,
|
|
284
|
+
local=run_config.local,
|
|
285
|
+
watch=run_config.watch,
|
|
286
|
+
auth_info=run_config.auth_info,
|
|
292
287
|
)
|
|
293
288
|
if run_config.watch:
|
|
294
289
|
featureset.reload()
|