Skip to content

UAF ART-layer features ('uaf art view')

Register a UAF (Unbounded Array Framework) feature whose value lives in a secondary ART (Analytical Result Table) layer as a governed, run()-recomputable tdfs4ds feature — ARIMA fit-metrics (R_SQUARE/MAPE/AIC in ARTFITMETADATA), residual-adequacy tests over ARTFITRESIDUALS (Ljung-Box / Durbin-Watson / Breusch-Godfrey), TD_PACF, and similar.

Why a dedicated process type

A UAF operator whose entire result is in its inline output — TD_ACF, TD_DICKEY_FULLER — can be served by wrapping the inline EXECUTE FUNCTION inside a REPLACE VIEW and registering it as an ordinary 'denormalized view'. But a feature whose value lives in a secondary layer needs two statements:

  1. materialise the operator's ART, then
  2. TD_EXTRACT_RESULTS over a named LAYER of that ART.

tdfs4ds ingestion is a single CREATE VOLATILE TABLE AS (SELECT * FROM <view>), with nowhere to run the first statement — and every attempt to fold both into one object is rejected by Vantage (nested EXECUTE FUNCTION → 3706, INTO ART in a view → 3707, multi-statement view/macro → 3576).

The 'uaf art view' process type (v0.3.1.143) closes this gap. It stores the ART-materialising statements as art_sql and runs them per FilterManager partition, in the same session, immediately before the ingestion CTAS — so the session-scoped volatile ART is visible to the CTAS reading the feature view.

The model — one feature view + art_sql + art_layers

A 'uaf art view' process stores three things:

Piece What
art_sql A list of EXECUTE FUNCTION ... INTO VOLATILE ART(<name>) statements. Session-scoped: no PERM, auto-cleaned. Stored in the process METADATA JSON column — no DDL migration.
art_layers The declared LAYER(...) name(s) the feature view reads (e.g. ['ARTFITMETADATA']). Used for documentation and lineage.
the feature view The ordinary feature view, reading each layer via TD_EXTRACT_RESULTS(ART_SPEC(TABLE_NAME(<art>), LAYER(<layer>))).

Order matters in art_sql

Statements execute in list order, and a later statement may read an ART an earlier one created (chained operators — e.g. a residual test over the ARTFITRESIDUALS layer of an ARIMA fit). A JSON array preserves that order; never sort or reorder art_sql.

Full example — ARIMA fit-metrics (R_SQUARE + MAPE)

import teradataml as tdml
import tdfs4ds
from tdfs4ds import upload_features
from tdfs4ds.utils.filter_management import FilterManager

DB = 'MY_FS'; SRC = 'MY_SRC'
tdfs4ds.SCHEMA = DB
tdfs4ds.DATA_DOMAIN = 'FORECASTABILITY'

# 1. FilterManager over the series id (one model per series/partition)
fm = FilterManager(table_name='fm_series', schema_name=DB)
fm.load_filter(tdml.DataFrame.from_query(f"SELECT DISTINCT item_id FROM {SRC}.sales"))

# 2. series-input view — the store filter lives here as a scalar subquery
#    (partition-aware, no templating)
tdml.execute_sql(f"""
REPLACE VIEW {DB}.vw_series_in AS
LOCKING ROW FOR ACCESS
SELECT item_id,
       ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY cal_date) AS seq_no,
       sales_qty
FROM {SRC}.sales
WHERE item_id = (SELECT item_id FROM {fm.schema_name}.{fm.view_name})
""")

# 3. art_sql — materialise the ARIMA ART with FIT_METRICS(1) (generates ARTFITMETADATA)
art_sql = [f"""
EXECUTE FUNCTION INTO VOLATILE ART(arima_fit)
  TD_ARIMAESTIMATE(
    SERIES_SPEC(TABLE_NAME({DB}.vw_series_in), ROW_AXIS(SEQUENCE(seq_no)),
      SERIES_ID(item_id), PAYLOAD(FIELDS(sales_qty), CONTENT(REAL))),
    FUNC_PARAMS(NONSEASONAL(MODEL_ORDER(1,0,0)), CONSTANT(1), ALGORITHM(MLE),
      FIT_PERCENTAGE(100), FIT_METRICS(1)))
"""]

# 4. materialise the ART ONCE, then create the feature view (see lifecycle note below)
fm.update(1)
tdml.execute_sql(art_sql[0])
tdml.execute_sql(f"""
REPLACE VIEW {DB}.vw_feat_arima_fit AS
LOCKING ROW FOR ACCESS
SELECT item_id,
       CAST(R_SQUARE AS FLOAT) AS r_square,
       CAST(MAPE     AS FLOAT) AS mape
FROM ( EXECUTE FUNCTION TD_EXTRACT_RESULTS(
         ART_SPEC(TABLE_NAME(arima_fit), LAYER(ARTFITMETADATA))) ) x
""")

# 5. register + ingest — art_sql runs per partition, before the CTAS
upload_features(
    tdml.DataFrame(tdml.in_schema(DB, 'vw_feat_arima_fit')),
    entity_id     = ['item_id'],
    feature_names = ['r_square', 'mape'],
    art_sql       = art_sql,
    art_layers    = ['ARTFITMETADATA'],
    filtermanager = fm,          # tdfs4ds drives its own per-partition loop
    metadata      = {'project': 'forecastability'},
    # optimize_query is force-disabled for a uaf art view; document=True is fine.
)

Verified grammar (Vantage 20)

  • TD_EXTRACT_RESULTS is invoked via EXECUTE FUNCTION inside a derived table — FROM ( EXECUTE FUNCTION TD_EXTRACT_RESULTS(ART_SPEC(TABLE_NAME(<art>), LAYER(<layer>))) ) x. A plain FROM TD_EXTRACT_RESULTS(...) is a syntax error (3707).
  • TD_ARIMAESTIMATE uses FUNC_PARAMS(NONSEASONAL(MODEL_ORDER(p,d,q)), CONSTANT(1), ALGORITHM(MLE), FIT_PERCENTAGE(100), FIT_METRICS(1)). FIT_METRICS(1) generates the ARTFITMETADATA layer; RESIDUALS(1) generates ARTFITRESIDUALS.
  • The ARTFITMETADATA layer projects named columns (item_id, ROW_I, NUM_SAMPLES, R_SQUARE, R_ADJ_SQUARE, MAE, MSE, MAPE, …), one row per series — not a METRIC/VALUE key-value shape. Confirm the exact columns against your Vantage build.

Creation-time lifecycle constraint

A view referencing a volatile ART cannot be REPLACE VIEW-created unless that ART already exists in the session (Error 3807). So materialise the ART once (EXECUTE FUNCTION ... INTO VOLATILE ART) before creating the feature view (step 4 above). The permanent view then survives across sessions, but reading it always needs the ART present — which run() guarantees by re-materialising the ART per partition before each ingestion.

What run() does for this type

Per FilterManager partition: filtermanager.update() → DROP TABLE <art> then execute each art_sql statement (materialise the volatile ART) → ingest from the feature view (which reads the ART layer) → close follow-up. run(process_id, force_compute=True) re-materialises and re-ingests idempotently.

AI features, lineage, gates

  • optimize_query is force-disabled — art_sql is an opaque UAF invocation and the view EXPLAIN needs the ART materialised first.
  • Documentation skips the view-EXPLAIN and feeds the art_sql operator + art_layers into the column-documentation context (grounding the layer columns in the real computation). get_process_info surfaces ART_SQL/ART_LAYERS.
  • Lineage traces through the ephemeral ART — the dangling feature_view → <volatile ART> edge is rewritten to feature_view → <operator/layer node> → series_input_source (parsed from art_sql).