def apply_feature_view(self, feature_view: FeatureView, project: str, commit: bool = True): """ Registers a single feature view with Feast Args: feature_view: Feature view that will be registered project: Feast project that this feature view belongs to commit: Whether the change should be persisted immediately """ feature_view.is_valid() feature_view_proto = feature_view.to_proto() feature_view_proto.spec.project = project self._prepare_registry_for_changes() assert self.cached_registry_proto for idx, existing_feature_view_proto in enumerate( self.cached_registry_proto.feature_views): if (existing_feature_view_proto.spec.name == feature_view_proto.spec.name and existing_feature_view_proto.spec.project == project): if FeatureView.from_proto( existing_feature_view_proto) == feature_view: return else: del self.cached_registry_proto.feature_views[idx] break self.cached_registry_proto.feature_views.append(feature_view_proto) if commit: self.commit()
def plan(self, config: RepoConfig, desired_registry_proto: RegistryProto) -> List[InfraObject]: project = config.project infra_objects: List[InfraObject] = [ SqliteTable( path=self._get_db_path(config), name=_table_id(project, FeatureView.from_proto(view)), ) for view in desired_registry_proto.feature_views ] return infra_objects
def from_proto(cls, on_demand_feature_view_proto: OnDemandFeatureViewProto): """ Creates an on demand feature view from a protobuf representation. Args: on_demand_feature_view_proto: A protobuf representation of an on-demand feature view. Returns: A OnDemandFeatureView object based on the on-demand feature view protobuf. """ inputs = {} for ( input_name, on_demand_input, ) in on_demand_feature_view_proto.spec.inputs.items(): if on_demand_input.WhichOneof("input") == "feature_view": inputs[input_name] = FeatureView.from_proto( on_demand_input.feature_view).projection elif on_demand_input.WhichOneof( "input") == "feature_view_projection": inputs[input_name] = FeatureViewProjection.from_proto( on_demand_input.feature_view_projection) else: inputs[input_name] = RequestDataSource.from_proto( on_demand_input.request_data_source) on_demand_feature_view_obj = cls( name=on_demand_feature_view_proto.spec.name, features=[ Feature( name=feature.name, dtype=ValueType(feature.value_type), labels=dict(feature.labels), ) for feature in on_demand_feature_view_proto.spec.features ], inputs=inputs, udf=dill.loads( on_demand_feature_view_proto.spec.user_defined_function.body), ) # FeatureViewProjections are not saved in the OnDemandFeatureView proto. # Create the default projection. on_demand_feature_view_obj.projection = FeatureViewProjection.from_definition( on_demand_feature_view_obj) if on_demand_feature_view_proto.meta.HasField("created_timestamp"): on_demand_feature_view_obj.created_timestamp = ( on_demand_feature_view_proto.meta.created_timestamp.ToDatetime( )) return on_demand_feature_view_obj
def list_feature_views(self, project: str) -> List[FeatureView]: """ Retrieve a list of feature views from the registry Args: project: Filter feature tables based on project name Returns: List of feature tables """ registry_proto = self._registry_store.get_registry() feature_views = [] for feature_view_proto in registry_proto.feature_views: if feature_view_proto.spec.project == project: feature_views.append( FeatureView.from_proto(feature_view_proto)) return feature_views
def get_feature_view(self, name: str, project: str) -> FeatureView: """ Retrieves a feature view. Args: name: Name of feature view project: Feast project that this feature view belongs to Returns: Returns either the specified feature view, or raises an exception if none is found """ registry_proto = self._get_registry_proto() for feature_view_proto in registry_proto.feature_views: if (feature_view_proto.spec.name == name and feature_view_proto.spec.project == project): return FeatureView.from_proto(feature_view_proto) raise FeatureViewNotFoundException(name, project)
def list_feature_views( self, project: str, allow_cache: bool = False ) -> List[FeatureView]: """ Retrieve a list of 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 feature views """ registry_proto = self._get_registry_proto(allow_cache=allow_cache) feature_views = [] for feature_view_proto in registry_proto.feature_views: if feature_view_proto.spec.project == project: feature_views.append(FeatureView.from_proto(feature_view_proto)) return feature_views
def updater(registry_proto: RegistryProto): for idx, existing_feature_view_proto in enumerate( registry_proto.feature_views ): if ( existing_feature_view_proto.spec.name == feature_view.name and existing_feature_view_proto.spec.project == project ): existing_feature_view = FeatureView.from_proto( existing_feature_view_proto ) existing_feature_view.materialization_intervals.append( (start_date, end_date) ) feature_view_proto = existing_feature_view.to_proto() feature_view_proto.spec.project = project del registry_proto.feature_views[idx] registry_proto.feature_views.append(feature_view_proto) return registry_proto raise FeatureViewNotFoundException(feature_view.name, project)
def apply_materialization( self, feature_view: FeatureView, project: str, start_date: datetime, end_date: datetime, commit: bool = True, ): """ Updates materialization intervals tracked for a single feature view in Feast Args: feature_view: Feature view that will be updated with an additional materialization interval tracked project: Feast project that this feature view belongs to start_date (datetime): Start date of the materialization interval to track end_date (datetime): End date of the materialization interval to track commit: Whether the change should be persisted immediately """ self._prepare_registry_for_changes() assert self.cached_registry_proto for idx, existing_feature_view_proto in enumerate( self.cached_registry_proto.feature_views): if (existing_feature_view_proto.spec.name == feature_view.name and existing_feature_view_proto.spec.project == project): existing_feature_view = FeatureView.from_proto( existing_feature_view_proto) existing_feature_view.materialization_intervals.append( (start_date, end_date)) existing_feature_view.last_updated_timestamp = datetime.utcnow( ) feature_view_proto = existing_feature_view.to_proto() feature_view_proto.spec.project = project del self.cached_registry_proto.feature_views[idx] self.cached_registry_proto.feature_views.append( feature_view_proto) if commit: self.commit() return raise FeatureViewNotFoundException(feature_view.name, project)
def updater(registry_proto: RegistryProto): for idx, existing_feature_view_proto in enumerate( registry_proto.feature_views ): if ( existing_feature_view_proto.spec.name == feature_view_proto.spec.name and existing_feature_view_proto.spec.project == project ): # do not update if feature view has not changed; updating will erase tracked materialization intervals if ( FeatureView.from_proto(existing_feature_view_proto) == feature_view ): return registry_proto else: del registry_proto.feature_views[idx] registry_proto.feature_views.append(feature_view_proto) return registry_proto registry_proto.feature_views.append(feature_view_proto) return registry_proto
def from_proto(cls, on_demand_feature_view_proto: OnDemandFeatureViewProto): """ Creates an on demand feature view from a protobuf representation. Args: on_demand_feature_view_proto: A protobuf representation of an on-demand feature view. Returns: A OnDemandFeatureView object based on the on-demand feature view protobuf. """ inputs = {} for ( input_name, on_demand_input, ) in on_demand_feature_view_proto.spec.inputs.items(): if on_demand_input.WhichOneof("input") == "feature_view": inputs[input_name] = FeatureView.from_proto( on_demand_input.feature_view) else: inputs[input_name] = RequestDataSource.from_proto( on_demand_input.request_data_source) on_demand_feature_view_obj = cls( name=on_demand_feature_view_proto.spec.name, features=[ Feature( name=feature.name, dtype=ValueType(feature.value_type), labels=dict(feature.labels), ) for feature in on_demand_feature_view_proto.spec.features ], inputs=inputs, udf=dill.loads( on_demand_feature_view_proto.spec.user_defined_function.body), ) return on_demand_feature_view_obj
def from_proto(cls, on_demand_feature_view_proto: OnDemandFeatureViewProto): """ Creates an on demand feature view from a protobuf representation. Args: on_demand_feature_view_proto: A protobuf representation of an on-demand feature view. Returns: A OnDemandFeatureView object based on the on-demand feature view protobuf. """ sources = [] for ( _, on_demand_source, ) in on_demand_feature_view_proto.spec.sources.items(): if on_demand_source.WhichOneof("source") == "feature_view": sources.append( FeatureView.from_proto( on_demand_source.feature_view).projection) elif on_demand_source.WhichOneof( "source") == "feature_view_projection": sources.append( FeatureViewProjection.from_proto( on_demand_source.feature_view_projection)) else: sources.append( RequestSource.from_proto( on_demand_source.request_data_source)) on_demand_feature_view_obj = cls( name=on_demand_feature_view_proto.spec.name, schema=[ Field( name=feature.name, dtype=from_value_type(ValueType(feature.value_type)), ) for feature in on_demand_feature_view_proto.spec.features ], sources=sources, udf=dill.loads( on_demand_feature_view_proto.spec.user_defined_function.body), description=on_demand_feature_view_proto.spec.description, tags=dict(on_demand_feature_view_proto.spec.tags), owner=on_demand_feature_view_proto.spec.owner, ) # FeatureViewProjections are not saved in the OnDemandFeatureView proto. # Create the default projection. on_demand_feature_view_obj.projection = FeatureViewProjection.from_definition( on_demand_feature_view_obj) if on_demand_feature_view_proto.meta.HasField("created_timestamp"): on_demand_feature_view_obj.created_timestamp = ( on_demand_feature_view_proto.meta.created_timestamp.ToDatetime( )) if on_demand_feature_view_proto.meta.HasField( "last_updated_timestamp"): on_demand_feature_view_obj.last_updated_timestamp = ( on_demand_feature_view_proto.meta.last_updated_timestamp. ToDatetime()) return on_demand_feature_view_obj