1.7 Creating a Feature Table and Writing Data to It
Key Takeaways
- `FeatureEngineeringClient.create_table(name, primary_keys, df=..., timeseries_column=...)` creates a Delta-backed feature table under a three-level Unity Catalog name.
- Primary keys are mandatory — they are what `FeatureLookup` joins on later, so a table without them cannot be used for training-set construction.
- `timeseries_column` is a single column name (not a list) and is required only when the table will serve point-in-time lookups.
- `fe.write_table(name, df, mode='merge')` upserts on the primary keys; `mode='overwrite'` replaces the table contents wholesale.
- Supplying `df` at creation defines the schema and loads the initial rows; supplying `schema` instead creates an empty table to be populated later by `write_table`.
1.7 Creating a Feature Table and Writing Data to It
Creating a feature table is a two-step act: define the table with its keys and
schema, then write feature values into it on a schedule. Both steps go through
FeatureEngineeringClient, and both are directly examinable.
Initializing and Creating Feature Tables
Feature tables in Unity Catalog are standard Delta Lake tables augmented with explicit feature metadata (such as primary key constraints). Creating and writing to feature tables is managed via the FeatureEngineeringClient.
Step 1: Client Initialization and Table Creation
from databricks.feature_engineering import FeatureEngineeringClient
from pyspark.sql import functions as F
# Initialize modern Feature Engineering Client
fe = FeatureEngineeringClient()
# Compute feature DataFrame with business aggregation logic
raw_transactions = spark.table("prod_catalog.source_data.transactions")
customer_features_df = raw_transactions.groupBy("customer_id").agg(
F.count("transaction_id").alias("total_tx_count"),
F.avg("amount").alias("avg_transaction_amount"),
F.max("transaction_date").alias("last_transaction_date")
)
# Define the full 3-level table name
feature_table_name = "prod_catalog.ml_features.customer_spending_features"
# Create the feature table in Unity Catalog
fe.create_table(
name=feature_table_name,
primary_keys=["customer_id"],
df=customer_features_df,
description="Aggregated customer lifetime transaction and spending metrics",
tags={"domain": "finance", "tier": "gold"}
)
Key Parameters of fe.create_table
name: Fully qualified 3-level name (catalog.schema.table).primary_keys: List of column names that uniquely identify entity records (e.g.,["customer_id"]or composite keys["user_id", "device_id"]). Primary keys are mandatory for feature lookups.timeseries_column: (Optional, singular string) The single column holding the timestamp of each feature observation. Required when the table will be used for point-in-time lookups. Writingtimeseries_columns=[...]is a common and incorrect guess — the parameter takes one column name, not a list.df: Optional PySpark DataFrame used to populate the table schema and initial data.schema: ExplicitStructTypeschema (required ifdfis omitted).
Writing and Updating Feature Tables
Feature values change continuously as new batch or streaming transactions arrive. The FeatureEngineeringClient.write_table API provides controlled update semantics:
# Incremental daily batch update
new_daily_features_df = compute_daily_customer_features()
# Upsert features into Unity Catalog table
fe.write_table(
name="prod_catalog.ml_features.customer_spending_features",
df=new_daily_features_df,
mode="merge" # Performs Delta Lake MERGE on primary keys
)
Write Modes Supported
mode="merge"(Recommended): Performs an intelligent Delta LakeMERGE(upsert) operation using the table's definedprimary_keys. If an incoming entity record already exists, its feature values are updated; if the entity is new, a new row is inserted.mode="overwrite": Completely truncates and replaces the existing feature table contents with the incoming DataFrame. Used for full historical recalculations.
Choosing Between the Creation Modes
| Situation | Call | Result |
|---|---|---|
| The feature DataFrame is already computed | create_table(name, primary_keys, df=features_df) | Schema inferred from df, rows written immediately |
| The table must exist before any data is produced (e.g. a streaming writer fills it) | create_table(name, primary_keys, schema=struct_type) | Empty governed table with the declared schema |
| The table already exists and new values arrived | write_table(name, df, mode="merge") | Upsert on the primary keys |
| Feature logic changed and history must be recomputed | write_table(name, df, mode="overwrite") | Contents replaced |
Rules that decide exam answers
- Primary keys are not optional. They are the join keys for
FeatureLookup. A table created without them cannot participate increate_training_set. - A composite key is a list:
primary_keys=["user_id", "device_id"]. The observation DataFrame must supply every key column at lookup time. timeseries_columntakes one string. It is only needed for point-in-time tables; a static entity table (demographics, product attributes) omits it.- Merge is keyed, not appended.
mode="merge"matches incoming rows to existing rows on the primary keys, updating matches and inserting new entities. It will not produce duplicate rows for the same key, which is exactly why it is the default for incremental refreshes. - Reading back is ordinary Delta.
fe.read_table(name=...)returns the feature table as a Spark DataFrame, andspark.table(name)works too — a feature table is a Delta table with extra metadata, not a special storage format.
Unity Catalog Governance, Search & Automated Lineage
Because feature tables in Unity Catalog are native Delta tables, enterprise security policies apply seamlessly:
-- Grant read permissions to data science group
GRANT SELECT ON TABLE prod_catalog.ml_features.customer_spending_features
TO `data-scientists`;
-- Grant write/update permissions to automated ETL service principal
GRANT MODIFY ON TABLE prod_catalog.ml_features.customer_spending_features
TO `sp-feature-pipeline`;
Automated Lineage Graph
Unity Catalog captures end-to-end lineage automatically without manual instrumentation:
- Upstream Lineage: Displays raw bronze/silver Delta source tables queried to build the feature table.
- Downstream Lineage: Automatically identifies which MLflow training runs, registered models, and scheduled batch inference pipelines consume features from the table.
[ Bronze Raw Logs ] ---> [ Silver Cleaned Data ] ---> [ Feature Table (Unity Catalog) ]
|
+-------------------------------+-------------------------------+
v v
[ MLflow Model Training Run ] [ Batch Scoring Pipeline ]
|
v
[ Registered Model in UC ]
What is the recommended import path and client initialization for working with feature tables in Unity Catalog on modern Databricks ML runtimes?
A data engineer creates a customer feature table in Unity Catalog that must support reliable point-in-time feature lookups during training. Which metadata must be declared on the table?
When updating an existing feature table using 'fe.write_table(name, df, mode=...)', which mode performs an incremental upsert based on the table's primary keys?