Skip to main content

fabric-mlv

Use for Fabric Materialized Lake Views (MLVs) — `CREATE MATERIALIZED LAKE VIEW` Spark SQL (GA March 2026) + still-preview `@fmlv.materialized_lake_view` PySpark decorator on a schema-enabled lakehouse (Runtime 1.3). Covers CREATE / SHOW / ALTER RENAME / DROP / REFRESH FULL syntax, `CONSTRAINT ... CHECK ... ON MISMATCH DROP|FAIL` data quality rules, partitioning/TBLPROPERTIES, optimal refresh (skip/incremental/full) + CDF prerequisite, the supported-SQL-constructs table, lineage-driven dependency ordering, scheduling (time-based vs event-triggered Preview, per-schedule Spark environment, Extended lineage across lakehouses/workspaces), `RefreshMaterializedLakeViews` REST job-type, run history (25 runs / 7 days), data quality report, gotchas: no ALTER definition only RENAME, no DML/UDF/temp views/time-travel, all-uppercase schemas rejected, names lowercased, `spark.conf.set` ignored on refresh, 24-hour run cap, overlapping refreshes skipped, PySpark always full-refresh, deleting defining notebook breaks refresh.

설치로 이동

소스 정보

저장소
wardawgmalvicious/agent-config
최근 소스 활동
2026년 9월 11일 15:49
감지된 SKILL.md 언어
영어
스타
1
포크
0

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
fabric-mlv
description
Use for Fabric Materialized Lake Views (MLVs) — `CREATE MATERIALIZED LAKE VIEW` Spark SQL (GA March 2026) + still-preview `@fmlv.materialized_lake_view` PySpark decorator on a schema-enabled lakehouse (Runtime 1.3). Covers CREATE / SHOW / ALTER RENAME / DROP / REFRESH FULL syntax, `CONSTRAINT ... CHECK ... ON MISMATCH DROP|FAIL` data quality rules, partitioning/TBLPROPERTIES, optimal refresh (skip/incremental/full) + CDF prerequisite, the supported-SQL-constructs table, lineage-driven dependency ordering, scheduling (time-based vs event-triggered Preview, per-schedule Spark environment, Extended lineage across lakehouses/workspaces), `RefreshMaterializedLakeViews` REST job-type, run history (25 runs / 7 days), data quality report, gotchas: no ALTER definition only RENAME, no DML/UDF/temp views/time-travel, all-uppercase schemas rejected, names lowercased, `spark.conf.set` ignored on refresh, 24-hour run cap, overlapping refreshes skipped, PySpark always full-refresh, deleting defining notebook breaks refresh.
disable-model-invocation
false
# Fabric Materialized Lake Views (MLV) Declarative SQL/PySpark transformations that persist as Delta tables in a schema-enabled lakehouse. Fabric handles refresh strategy, dependency order, and data quality enforcement so you don't write notebook orchestration. ## When to use vs not Use MLVs for medallion bronze→silver→gold pipelines, frequently-queried aggregates, declarative data quality, and reporting datasets that need automatic refresh. Skip them for one-off queries, sub-second streaming (use Real-Time Intelligence), or transformations that need ML inference / external API calls / non-SQL Python (use a regular Spark notebook). ## Prerequisites - **Schema-enabled lakehouse** — required. `enableSchemas` is immutable per lakehouse; you can't retrofit it. - **Fabric Runtime 1.3** — earlier runtimes can't author MLVs. Upstream still names 1.3 exactly (checked 2026-08-29), and **has not** extended the prerequisite to **Runtime 2.0** (GA Aug 2026 — Spark 4.1, Delta Lake 4.2, Python 3.13), so treat 2.0 as unverified for MLV authoring rather than assumed. This has a deadline: 2.0 is planned to become the default for new workspaces and environment items in **late September 2026**, at which point a new workspace stops defaulting to a runtime MLVs are documented against. Re-check the prerequisite then. - **Region** — not available in South Central US (as of 2026-04). - **CDF on source tables** — required for incremental refresh: `ALTER TABLE bronze.x SET TBLPROPERTIES (delta.enableChangeDataFeed = true)`. Without it, optimal refresh degrades to skip-or-full only. ## Spark SQL — CREATE ```sql CREATE [OR REPLACE] MATERIALIZED LAKE VIEW [IF NOT EXISTS] [workspace.lakehouse.schema].MLV_Identifier [( CONSTRAINT name1 CHECK (expr1) [ON MISMATCH DROP | FAIL], CONSTRAINT name2 CHECK (expr2) [ON MISMATCH DROP | FAIL] )] [PARTITIONED BY (col1, col2, ...)] [COMMENT "..."] [TBLPROPERTIES ("k1"="v1", ...)] AS select_statement ``` | Clause | Notes | |---|---| | `OR REPLACE` | Mutually exclusive with `IF NOT EXISTS` | | `CONSTRAINT ... CHECK` | Multiple allowed. Only deterministic built-ins permitted | | `ON MISMATCH DROP` | Silently drops violating rows. Each row dropped at most once even if it violates multiple constraints | | `ON MISMATCH FAIL` | Default. Stops the refresh with an error | | `PARTITIONED BY` | Improves filtered-read performance | | `TBLPROPERTIES` | Set `delta.enableChangeDataFeed=true` here to enable CDF on the MLV itself for downstream MLVs | Workspace names with spaces require backtick-quoting: `` `My Workspace`.lakehouse.schema.view_name ``. ```sql CREATE OR REPLACE MATERIALIZED LAKE VIEW silver.cleaned_orders ( CONSTRAINT valid_qty CHECK (quantity > 0) ON MISMATCH DROP ) PARTITIONED BY (category) TBLPROPERTIES (delta.enableChangeDataFeed=true) AS SELECT p.productID, p.category, o.orderDate, o.quantity, o.totalAmount FROM bronze.products p INNER JOIN bronze.orders o ON p.productID = o.productID; ``` ## Spark SQL — manage ```sql SHOW MATERIALIZED LAKE VIEWS IN silver; SHOW CREATE MATERIALIZED LAKE VIEW silver.cleaned_orders; ALTER MATERIALIZED LAKE VIEW silver.cleaned_orders RENAME TO silver.cleaned_orders_v2; DROP MATERIALIZED LAKE VIEW silver.cleaned_orders; REFRESH MATERIALIZED LAKE VIEW silver.cleaned_orders FULL; ``` You **cannot `ALTER` the definition** — only `RENAME`. To change `SELECT`, constraints, or partitioning: drop and recreate (or `CREATE OR REPLACE`). ## PySpark (`fmlv` — preview) Use when transformations need UDFs, external Python libraries, or reusable helper functions that are awkward in SQL. ```python import fmlv from pyspark.sql import functions as F @fmlv.materialized_lake_view( name="LH1.silver.customer_enriched", partition_cols=["year", "city"], table_properties={"delta.enableChangeDataFeed": "true"}, replace=True ) @fmlv.check("nonnull_sales", "sales IS NOT NULL", "drop") def customer_enriched(): df = spark.read.table("LH2.bronze.customer_bronze") return df.withColumn("sales_in_usd", F.col("sales") * 1.0) ``` ### Notebook organization rules (PySpark only) - **One `@fmlv` decorator per cell** — multiple per cell is unsupported. - Helper functions go in cells **above** the `@fmlv` cell. - The defining notebook **must not be deleted** — scheduled refresh re-executes its cells. Deletion silently breaks every MLV defined there. - After editing the decorator, **re-run the notebook** to register the change. Otherwise the next refresh executes the new code with stale registration metadata and may fail. - **No variables in `@fmlv` arguments** — all parameters must be hardcoded literals. `name=view_name` will not work. - Only `%%pyspark` and `%%sql` magics, and only at the top of a cell. - Don't mix MLV definitions with unrelated code in the same notebook. ### PySpark trade-offs vs SQL | Capability | Spark SQL | PySpark (`fmlv`) | |---|---|---| | Optimal (incremental) refresh | ✅ | ❌ — always full refresh or skip | | On-demand refresh from notebook | ✅ (`REFRESH ... FULL`) | ❌ — lineage-schedule only | | Rename via SQL | ✅ (`ALTER ... RENAME`) | ❌ — drop+recreate, or rename in lakehouse explorer | ## Optimal refresh Optimal refresh is on by default. Per-run, Fabric picks one of three strategies based on Delta commits on source tables: | Strategy | When | |---|---| | **Skip** | No new Delta commits on any source table | | **Incremental** | New commits + query uses only the supported-construct subset + all sources have CDF enabled + append-only | | **Full** | Source has updates/deletes, unsupported constructs, non-Delta source, or PySpark-defined MLV | Toggle: lakehouse → **Materialized lake views** → **Manage** → **Optimal refresh**. Off = every scheduled run does a full rebuild. A **schedule can override it** under its own **Advanced settings**; per-schedule settings beat lakehouse defaults, which beat system defaults. ### What blocks incremental refresh | Construct | Behavior | |---|---| | `SELECT` aggregates (`SUM`, `COUNT`, `AVG`, `MIN`, `MAX`, `STDDEV`) | Full refresh | | `GROUP BY`, `DISTINCT`, window functions | Full refresh | | Non-deterministic funcs (`rand()`, `uuid()`, `current_timestamp()`) | Full refresh | | `INNER JOIN`, `LEFT OUTER`, `LEFT SEMI`, `UNION ALL` | Incremental — but `LEFT` joins fall back to full if the right-side table changes | | Subqueries / `EXISTS` | Full refresh if any referenced table changes | | `WITH` (CTE) | Incremental if every clause inside is supported | | Source is non-Delta table | Always full refresh | Unsupported constructs **don't block creation** — they just downgrade to full refresh. Audit MLVs whose runs always show as Full when you expected Incremental. ## Lineage and scheduling When an MLV references another MLV or table, Fabric builds a dependency DAG (the **lineage view**). A schedule runs its scope in dependency order — you don't write orchestration. Multiple schedules can coexist on one lakehouse and **each runs independently**, so give separate lineages their own cadence rather than forcing everything onto one. UI path: lakehouse → **Materialized lake views** → **Manage** → **Manage schedules** → **New schedule**. Each schedule takes a name, an optional description, and a scope: **Refresh all materialized lake views** or **Refresh selected materialized lake view(s)** (any level of the lineage; selected views get a dashed border in the graph). ### Refresh type | Type | Detail | |---|---| | **Time-based** | Repeat by minute / hourly / daily / weekly / monthly, one or more time slots, start date, end date, time zone. | | **Event-triggered** (**Preview**) | Fires on an event instead of a clock. Event source type is **Job events** (Fabric Notebook or ADF pipeline completion) or **OneLake events** (ingestion into OneLake); then pick the event type and configure the source. | Use event-triggered when source arrival is unpredictable — a fixed cadence either wastes compute on no-op runs or lags the data. **Event-triggered gotchas.** Only OneLake events and Notebook / Pipeline job events are supported as sources. **Private Link is out of preview scope.** The mechanism depends on an auto-created **"FMLV Refresh" Notebook and Activator** pair in the workspace — they look like stray auto-generated items and they are load-bearing. Modifying or deleting them can silently stop event-triggered refreshes. ### Advanced settings | Setting | Detail | Default | |---|---|---| | **Spark environment** | Any Spark environment you have access to **within the same capacity**, including one in a different workspace. Changes apply on the next refresh. Lose access to it and you lose the **Schedule** and **Run** actions; delete it and the dropdown errors until you pick an accessible one. | Workspace default | | **Optimal refresh** | Per-schedule override of the lakehouse toggle. | On | Priority order: per-schedule → lakehouse-level → system defaults. ### Cross-lakehouse: Extended lineage MLV chains **can** span lakehouses, and workspaces. Turn on the **Extended lineage** toggle in the schedule configuration and a tree of every upstream lakehouse discovered through lineage appears; check the ones to include. **Leaving all of them unselected includes every lakehouse in the extended lineage** — the permissive default, not a no-op. The current lakehouse is always included implicitly. Fabric refreshes upstream views first, then downstream, across every included lakehouse; independent branches run in parallel; Recent runs shows a **single** run entry for the whole thing. So a Bronze → Silver → Gold flow across three lakehouses is one schedule defined in Gold, not three coordinated ones. Ad-hoc equivalent: **Run** on the lineage toolbar → **On demand lineage refresh**, then pick an execution mode — *Refresh without dependant lineage* (selected views only), *Refresh with dependant lineage* (plus upstream within the current lakehouse), or *Refresh with extended lineage* (plus upstream lakehouses, same tree). | Requirement | Detail | |---|---| | View an upstream lakehouse | `ReadAll` on it. With OneLake-based permissions enabled: `Read` on the required tables/MLVs. | | Include a lakehouse in the refresh | `ReadWrite` on it. With OneLake-based permissions enabled: `ReadWrite` on the required MLVs. | | Spark environment | Any you can access within the same capacity. | | Inaccessible dependencies | Show as **faulted nodes**. **Any faulted node blocks the whole lineage refresh** — it won't run at all. | | Maximum run duration | 24 hours, same as a standard run. | ### Run behavior A run **fails if it exceeds 24 hours**. If a refresh starts while another is still in progress, **Fabric skips the later one** — it is not queued. A schedule that "didn't run" is usually this. Run history retention: **last 25 runs OR last 7 days, whichever comes first**. | Run state | Meaning | |---|---| | `In progress` | Currently running | | `Success` | All views in DAG refreshed | | `Failed` | At least one view failed; downstream children auto-marked `Skipped` | | `Skipped` | Same view already refreshing in another active run | | `Canceled` | Manually canceled from Monitor hub | Note: Monitor hub may show a `Skipped` MLV run as `Canceled` — they're the same thing in the lineage view. ## REST API (job scheduler) `{jobType}` is `RefreshMaterializedLakeViews` for every MLV endpoint. ```http # On-demand refresh of the entire lineage POST /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/instances → 202 Accepted, Location: .../jobs/instances/{jobInstanceId} # Schedule CRUD POST /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/schedules GET /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/schedules GET /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/schedules/{id} PATCH /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/schedules/{id} DELETE /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/schedules/{id} # Job instance status / cancel GET /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/instances GET /v1/workspaces/{ws}/lakehouses/{lh}/jobs/instances/{jobInstanceId} POST /v1/workspaces/{ws}/lakehouses/{lh}/jobs/instances/{jobInstanceId}/cancel ``` Polling pattern: take `Location` from the 202, poll the `Get Item Job Instance` endpoint until `status` ≠ `InProgress`. Job-scheduler limits cap schedules-per-lakehouse and visible historical instances. ### Scoping a refresh — MLV execution definitions Without `executionData`, the on-demand refresh and a schedule created over REST refresh the whole lineage. An **MLV execution definition** is a saved selection — which MLVs, which upstream lakehouses, the refresh mode and the Spark environment — that a run or a schedule can be scoped to instead. ```http # Execution definition CRUD POST /v1/workspaces/{ws}/lakehouses/{lh}/mlvexecutiondefinitions → 201 Created, Location GET /v1/workspaces/{ws}/lakehouses/{lh}/mlvexecutiondefinitions → 200 GET /v1/workspaces/{ws}/lakehouses/{lh}/mlvexecutiondefinitions/{id} → 200 PATCH /v1/workspaces/{ws}/lakehouses/{lh}/mlvexecutiondefinitions/{id} → 200 DELETE /v1/workspaces/{ws}/lakehouses/{lh}/mlvexecutiondefinitions/{id} → 200 ``` Create body, from Learn's sample: ```json { "displayName": "Gold Chain – Sales", "description": "Nightly refresh for the Sales gold-layer views", "settings": { "environment": { "referenceType": "ById", "itemId": "<ENVIRONMENT_ID>", "workspaceId": "<ENVIRONMENT_WORKSPACE_ID>" }, "refreshMode": "Optimal" }, "currentLakehouseExecutionContext": { "mode": "Selected", "selectedMlvs": ["dbo.gold_sales_summary", "dbo.gold_sales_daily"] }, "extendedLineageExecutionContext": { "mode": "All" } } ``` `refreshMode` is `Optimal` or `Full`. Each execution context takes a `mode` of `All` or `Selected` — `selectedMlvs` for the current lakehouse, `selectedLakehouses` (`referenceType` / `itemId` / `workspaceId`) for extended lineage. To scope a run, send `executionData` with the on-demand refresh (`POST .../jobs/RefreshMaterializedLakeViews/instances` → `202 Accepted`, `Location`, `Retry-After: 60`), or with a schedule create (`POST .../schedules` → `201`) or update (`PATCH .../schedules/{id}` → `200`), where it sits beside `enabled` and `configuration`: ```json { "executionData": { "mlvExecutionDefinitionId": "<mlvExecutionDefinitionId>" } } ``` Two behaviours a caller won't guess: - **PATCH merges.** Only the fields in the body are updated; omitted fields keep their existing values. - **Deleting a definition deletes its schedules.** Any schedule linked to it is removed with it. ## Data quality report Auto-generated Power BI report tracking `CHECK` violations and `DROP` counts. Lakehouse → **Manage materialized lake views** → **Data quality report** → **Generate report**. - Two pages: **Overview** (last 7 days, top MLVs/constraints) and **MLV Detail** (filterable by `SchemaName` / `MLVName` / `RelativeDate`). - Built on DirectQuery — capped at **1M rows per query** on non-premium capacity. - Workspace/lakehouse names with special characters or spaces can fail report generation. - Recipients need at least `Read` or `ReadData` on the SQL analytics endpoint. - Violations ≥ drops (one row only ever dropped once even if it violates multiple constraints). ## Limitations and gotchas | Issue | Cause | Fix | |---|---|---| | MLV name unexpectedly lowercased | Names are case-insensitive, normalized to lowercase | Reference as lowercase everywhere; don't rely on `MyView` resolving distinct from `myview` | | `ALTER` to change SELECT fails | Only `RENAME` is supported via `ALTER` | Drop + recreate, or `CREATE OR REPLACE` | | `INSERT/UPDATE/DELETE` rejected | MLV is populated only by its `SELECT` | Modify the source table or rewrite the `SELECT` |
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기