Visitar URL original
feat: Offline store update pull_all_from_table_or_query to make timestampfield optional by haoxu0 · Pull Request #5281 · feast-dev/feast · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
update
Signed-off-by: HaoXuAI <sduxuhao@gmail.com>
  • Loading branch information
haoxu0 committed Apr 18, 2025
commit b62fd1a8be2cb8d613d36b11167b0e553bd38871
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@
SparkAggregationNode,
SparkDedupNode,
SparkFilterNode,
SparkHistoricalRetrievalReadNode,
SparkJoinNode,
SparkMaterializationReadNode,
SparkTransformationNode,
SparkWriteNode,
SparkWriteNode, SparkReadNode,
)


Expand All @@ -27,12 +25,10 @@ def __init__(
self.spark_session = spark_session

def build_source_node(self):
if isinstance(self.task, MaterializationTask):
node = SparkMaterializationReadNode("source", self.task)
else:
node = SparkHistoricalRetrievalReadNode(
"source", self.task, self.spark_session
)
source = self.feature_view.batch_source
start_time = self.task.start_time
end_time = self.task.end_time
node = SparkReadNode("source", source, start_time, end_time)
self.nodes.append(node)
return node

Expand Down
95 changes: 16 additions & 79 deletions sdk/python/feast/infra/compute_engines/spark/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pyspark.sql import DataFrame, SparkSession, Window
from pyspark.sql import functions as F

from data_source import DataSource
from feast import BatchFeatureView, StreamFeatureView
from feast.aggregation import Aggregation
from feast.infra.common.materialization_job import MaterializationTask
Expand Down Expand Up @@ -49,18 +50,21 @@ def rename_entity_ts_column(
return entity_df


class SparkMaterializationReadNode(DAGNode):
class SparkReadNode(DAGNode):
def __init__(
self, name: str, task: Union[MaterializationTask, HistoricalRetrievalTask]
self,
name: str,
source: DataSource,
start_time: Optional[timedelta] = None,
end_time: Optional[timedelta] = None,
):
super().__init__(name)
self.task = task
self.source = source
self.start_time = start_time
self.end_time = end_time

def execute(self, context: ExecutionContext) -> DAGValue:
offline_store = context.offline_store
start_time = self.task.start_time
end_time = self.task.end_time

(
join_key_columns,
feature_name_columns,
Expand All @@ -69,15 +73,14 @@ def execute(self, context: ExecutionContext) -> DAGValue:
) = context.column_info

# 📥 Reuse Feast's robust query resolver
retrieval_job = offline_store.pull_latest_from_table_or_query(
retrieval_job = offline_store.pull_all_from_table_or_query(
config=context.repo_config,
data_source=self.task.feature_view.batch_source,
data_source=self.source,
join_key_columns=join_key_columns,
feature_name_columns=feature_name_columns,
timestamp_field=timestamp_field,
created_timestamp_column=created_timestamp_column,
start_date=start_time,
end_date=end_time,
start_date=self.start_time,
end_date=self.end_time,
)
spark_df = cast(SparkRetrievalJob, retrieval_job).to_spark_df()

Expand All @@ -88,74 +91,8 @@ def execute(self, context: ExecutionContext) -> DAGValue:
"source": "feature_view_batch_source",
"timestamp_field": timestamp_field,
"created_timestamp_column": created_timestamp_column,
"start_date": start_time,
"end_date": end_time,
},
)


class SparkHistoricalRetrievalReadNode(DAGNode):
def __init__(
self, name: str, task: HistoricalRetrievalTask, spark_session: SparkSession
):
super().__init__(name)
self.task = task
self.spark_session = spark_session

def execute(self, context: ExecutionContext) -> DAGValue:
"""
Read data from the offline store on the Spark engine.
TODO: Some functionality is duplicated with SparkMaterializationReadNode and spark get_historical_features.
Args:
context: SparkExecutionContext
Returns: DAGValue
"""
fv = self.task.feature_view
source = fv.batch_source

(
join_key_columns,
feature_name_columns,
timestamp_field,
created_timestamp_column,
) = context.column_info

# TODO: Use pull_all_from_table_or_query when it supports not filtering by timestamp
# retrieval_job = offline_store.pull_all_from_table_or_query(
# config=context.repo_config,
# data_source=source,
# join_key_columns=join_key_columns,
# feature_name_columns=feature_name_columns,
# timestamp_field=timestamp_field,
# start_date=min_ts,
# end_date=max_ts,
# )
# spark_df = cast(SparkRetrievalJob, retrieval_job).to_spark_df()

columns = join_key_columns + feature_name_columns + [timestamp_field]
if created_timestamp_column:
columns.append(created_timestamp_column)

(fields_with_aliases, aliases) = _get_fields_with_aliases(
fields=columns,
field_mappings=source.field_mapping,
)
fields_with_alias_string = ", ".join(fields_with_aliases)

from_expression = source.get_table_query_string()

query = f"""
SELECT {fields_with_alias_string}
FROM {from_expression}
"""
spark_df = self.spark_session.sql(query)

return DAGValue(
data=spark_df,
format=DAGFormat.SPARK,
metadata={
"source": "feature_view_batch_source",
"timestamp_field": timestamp_field,
"start_date": self.start_time,
"end_date": self.end_time,
},
)

Expand Down
4 changes: 2 additions & 2 deletions sdk/python/feast/infra/offline_stores/offline_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ def pull_all_from_table_or_query(
join_key_columns: List[str],
feature_name_columns: List[str],
timestamp_field: str,
start_date: Optional[datetime],
end_date: Optional[datetime],
start_date: Optional[datetime] = None,
end_date: Optional[datetime] = None,
) -> RetrievalJob:
"""
Extracts all the entity rows (i.e. the combination of join key columns, feature columns, and
Expand Down