Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Registry and CLI operations for on demand feature views #1828

Merged
merged 1 commit into from
Sep 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions sdk/python/feast/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,58 @@ def feature_view_list(ctx: click.Context):
print(tabulate(table, headers=["NAME", "ENTITIES"], tablefmt="plain"))


@cli.group(name="on-demand-feature-views")
def on_demand_feature_views_cmd():
"""
Access feature views
"""
pass


@on_demand_feature_views_cmd.command("describe")
@click.argument("name", type=click.STRING)
@click.pass_context
def on_demand_feature_view_describe(ctx: click.Context, name: str):
"""
Describe an on demand feature view
"""
repo = ctx.obj["CHDIR"]
cli_check_repo(repo)
store = FeatureStore(repo_path=str(repo))

try:
on_demand_feature_view = store.get_on_demand_feature_view(name)
except FeastObjectNotFoundException as e:
print(e)
exit(1)

print(
yaml.dump(
yaml.safe_load(str(on_demand_feature_view)),
default_flow_style=False,
sort_keys=False,
)
)


@on_demand_feature_views_cmd.command(name="list")
@click.pass_context
def on_demand_feature_view_list(ctx: click.Context):
"""
List all on demand feature views
"""
repo = ctx.obj["CHDIR"]
cli_check_repo(repo)
store = FeatureStore(repo_path=str(repo))
table = []
for on_demand_feature_view in store.list_on_demand_feature_views():
table.append([on_demand_feature_view.name])

from tabulate import tabulate

print(tabulate(table, headers=["NAME"], tablefmt="plain"))


@cli.command("apply", cls=NoOptionDefaultFormat)
@click.option(
"--skip-source-validation",
Expand Down
10 changes: 10 additions & 0 deletions sdk/python/feast/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ def __init__(self, name, project=None):
super().__init__(f"Feature view {name} does not exist")


class OnDemandFeatureViewNotFoundException(FeastObjectNotFoundException):
def __init__(self, name, project=None):
if project:
super().__init__(
f"On demand feature view {name} does not exist in project {project}"
)
else:
super().__init__(f"On demand feature view {name} does not exist")


class FeatureTableNotFoundException(FeastObjectNotFoundException):
def __init__(self, name, project=None):
if project:
Expand Down
26 changes: 26 additions & 0 deletions sdk/python/feast/feature_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,16 @@ def list_feature_views(self) -> List[FeatureView]:
"""
return self._registry.list_feature_views(self.project)

@log_exceptions_and_usage
def list_on_demand_feature_views(self) -> List[OnDemandFeatureView]:
"""
Retrieves the list of on demand feature views from the registry.

Returns:
A list of on demand feature views.
"""
return self._registry.list_on_demand_feature_views(self.project)

@log_exceptions_and_usage
def get_entity(self, name: str) -> Entity:
"""
Expand Down Expand Up @@ -218,6 +228,22 @@ def get_feature_view(self, name: str) -> FeatureView:
"""
return self._registry.get_feature_view(name, self.project)

@log_exceptions_and_usage
def get_on_demand_feature_view(self, name: str) -> OnDemandFeatureView:
"""
Retrieves a feature view.

Args:
name: Name of feature view.

Returns:
The specified feature view.

Raises:
FeatureViewNotFoundException: The feature view could not be found.
"""
return self._registry.get_on_demand_feature_view(name, self.project)

@log_exceptions_and_usage
def delete_feature_view(self, name: str):
"""
Expand Down
70 changes: 48 additions & 22 deletions sdk/python/feast/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
FeatureServiceNotFoundException,
FeatureTableNotFoundException,
FeatureViewNotFoundException,
OnDemandFeatureViewNotFoundException,
S3RegistryBucketForbiddenAccess,
S3RegistryBucketNotExist,
)
Expand Down Expand Up @@ -339,6 +340,53 @@ def apply_on_demand_feature_view(
if commit:
self.commit()

def list_on_demand_feature_views(
self, project: str, allow_cache: bool = False
) -> List[OnDemandFeatureView]:
"""
Retrieve a list of on demand feature views from the registry

Args:
allow_cache: Whether to allow returning on demand feature views from a cached registry
project: Filter on demand feature views based on project name

Returns:
List of on demand feature views
"""

registry = self._get_registry_proto(allow_cache=allow_cache)
on_demand_feature_views = []
for on_demand_feature_view in registry.on_demand_feature_views:
if on_demand_feature_view.spec.project == project:
on_demand_feature_views.append(
OnDemandFeatureView.from_proto(on_demand_feature_view)
)
return on_demand_feature_views

def get_on_demand_feature_view(
self, name: str, project: str, allow_cache: bool = False
) -> OnDemandFeatureView:
"""
Retrieves an on demand feature view.

Args:
name: Name of on demand feature view
project: Feast project that this on demand feature belongs to

Returns:
Returns either the specified on demand feature view, or raises an exception if
none is found
"""
registry = self._get_registry_proto(allow_cache=allow_cache)

for on_demand_feature_view in registry.on_demand_feature_views:
if (
on_demand_feature_view.spec.project == project
and on_demand_feature_view.spec.name == name
):
return OnDemandFeatureView.from_proto(on_demand_feature_view)
raise OnDemandFeatureViewNotFoundException(name, project=project)

def apply_materialization(
self,
feature_view: FeatureView,
Expand Down Expand Up @@ -420,28 +468,6 @@ def list_feature_views(
feature_views.append(FeatureView.from_proto(feature_view_proto))
return feature_views

def list_on_demand_feature_views(
self, project: str, allow_cache: bool = False
) -> List[OnDemandFeatureView]:
"""
Retrieve a list of on demand feature views from the registry

Args:
allow_cache: Allow returning feature views from the cached registry
project: Filter feature tables based on project name

Returns:
List of on demand feature views
"""
registry_proto = self._get_registry_proto(allow_cache=allow_cache)
on_demand_feature_views = []
for on_demand_feature_view_proto in registry_proto.on_demand_feature_views:
if on_demand_feature_view_proto.spec.project == project:
on_demand_feature_views.append(
OnDemandFeatureView.from_proto(on_demand_feature_view_proto)
)
return on_demand_feature_views

def get_feature_table(self, name: str, project: str) -> FeatureTable:
"""
Retrieves a feature table.
Expand Down