算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
data-science-analytics-engineering【设计与创意】Use this skill when asked about analytics engineering, dbt, data modeling, metrics layer, semantic layer, Cube.js, MetricFlow, dbt metrics, SQL analytics, window functions, CTEs, pivot/unpivot, data modeling for analytics, OBT, dimensional modeling, medallion architecture, bronze/silver/gold, or analytical SQL. This skill enforces: dbt Core (models i…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Design and build production analytics pipelines with dbt Core (models, materializations, Jinja macros, ref/source, tests, documentation), metrics and semantic layers (dbt Metrics, MetricFlow, Cube.js, metric definitions, dimensions, filters, time granularity), data modeling for analytics (marts approach, One Big Table, dimensional modeling, medallion architecture), and analytical SQL (window functions, CTEs, pivoting, statistical functions, time series, performance optimization, UDFs).
Exact user phrases: "analytics engineering", "dbt", "dbt model", "dbt materialization", "Jinja macro", "dbt ref", "dbt source", "dbt test", "dbt doc", "metrics layer", "semantic layer", "MetricFlow", "Cube.js", "dbt metrics", "data modeling", "marts approach", "OBT", "One Big Table", "dimensional modeling", "medallion architecture", "bronze silver gold", "SQL analytics", "window function", "CTE", "pivot", "unpivot", "analytical SQL", "time series SQL", "SQL UDF".
Before activating, verify:
dbt project configuration, model SQL, macro definitions, metric definitions, data model documentation, and analytical query patterns.
-- dbt model code
-- Analytical SQL queries
-- dbt project config, schema.yml, metrics definitions
-- Python dbt models
-- MetricFlow config
No preamble. No postamble. No explanations. No filler/hedging/transitions. Compress output — why use many token when few do trick.
400 lines of code and configuration.
analytics/
├── models/
│ ├── staging/ # Raw → clean, typed, renamed
│ │ ├── stg_orders.sql
│ │ └── sources.yml
│ ├── intermediate/ # Business logic, joins, aggregations
│ │ ├── int_order_items.sql
│ │ └── int_customer_orders.sql
│ └── marts/ # Consumption-ready
│ ├── fct_orders.sql
│ ├── dim_customers.sql
│ └── marketing/
│ └── rpt_daily_revenue.sql
├── tests/ # Singular tests
│ └── assert_positive_revenue.sql
├── macros/ # Jinja macros
│ └── grant_permissions.sql
├── analyses/ # Ad-hoc queries
├── snapshots/ # Type-2 slowly changing dimensions
├── seeds/ # Static CSV data
└── dbt_project.yml
# models/staging/sources.yml
version: 2
sources:
- name: raw_shop
database: raw_db
schema: public
tables:
- name: orders
loaded_at_field: created_at
freshness:
warn_after: { count: 6, period: hour }
error_after: { count: 12, period: hour }
- name: customers
- name: products
-- models/staging/stg_orders.sql
WITH source AS (
SELECT * FROM {{ source('raw_shop', 'orders') }}
),
renamed AS (
SELECT
id AS order_id,
customer_id,
order_date::DATE AS order_date,
status,
total_amount::DECIMAL(10,2) AS total_amount,
created_at,
updated_at
FROM source
WHERE id IS NOT NULL
)
SELECT * FROM renamed
-- models/intermediate/int_customer_orders.sql
WITH customer_orders AS (
SELECT
customer_id,
MIN(order_date) AS first_order_date,
MAX(order_date) AS most_recent_order_date,
COUNT(order_id) AS number_of_orders,
SUM(total_amount) AS lifetime_value
FROM {{ ref('stg_orders') }}
WHERE status != 'cancelled'
GROUP BY 1
)
SELECT * FROM customer_orders
-- models/marts/dim_customers.sql
WITH customers AS (
SELECT * FROM {{ ref('stg_customers') }}
),
customer_orders AS (
SELECT * FROM {{ ref('int_customer_orders') }}
)
SELECT
customers.customer_id,
customers.first_name,
customers.last_name,
customers.email,
customer_orders.first_order_date,
customer_orders.most_recent_order_date,
COALESCE(customer_orders.number_of_orders, 0) AS number_of_orders,
COALESCE(customer_orders.lifetime_value, 0) AS lifetime_value
FROM customers
LEFT JOIN customer_orders ON customers.customer_id = customer_orders.customer_id
# dbt_project.yml
models:
analytics:
staging:
+materialized: view
+schema: staging
intermediate:
+materialized: ephemeral
marts:
+materialized: table
+schema: marts
marts_marketing:
+materialized: incremental
+schema: marketing
+incremental_strategy: merge
-- Incremental model example
{{ config(
materialized='incremental',
unique_key='order_date',
incremental_strategy='merge'
) }}
SELECT
order_date,
COUNT(DISTINCT order_id) AS total_orders,
SUM(total_amount) AS total_revenue,
COUNT(DISTINCT customer_id) AS active_customers
FROM {{ ref('stg_orders') }}
WHERE status = 'completed'
{% if is_incremental() %}
AND order_date >= (SELECT MAX(order_date) FROM {{ this }})
{% endif %}
GROUP BY order_date
# models/marts/schema.yml — dbt Metrics
version: 2
metrics:
- name: total_revenue
label: Total Revenue
model: ref('fct_orders')
description: "Sum of completed order amounts"
calculation_method: sum
expression: total_amount
timestamp: order_date
time_grains: [day, week, month, quarter, year]
dimensions:
- customer_tier
- product_category
- region
filters:
- field: status
operator: =
value: completed
- name: revenue_per_customer
label: Revenue Per Customer
description: "Average revenue per active customer"
calculation_method: derived
expression: "{{ metric('total_revenue') }} / {{ metric('active_customers') }}"
timestamp: order_date
time_grains: [month, quarter, year]
# models/marts/schema.yml
models:
- name: dim_customers
description: "Customer dimension with aggregated order history"
columns:
- name: customer_id
tests: [unique, not_null]
description: "Primary key from source system"
- name: email
tests:
- unique
- not_null
- accepted_values:
values: ["@"]
quote: false
- name: lifetime_value
tests:
- not_null
- dbt_utils.accepted_range:
min_value: 0
- name: first_order_date
tests:
- not_null
- dbt_expectations.expect_column_values_to_be_between:
min_value: '2020-01-01'
packages:
- package: dbt-labs/dbt_utils
version: ">=1.1.0"
macros:
- dbt_utils.star() # Select all columns except excluded
- dbt_utils.surrogate_key() # Generate unique row keys
- dbt_utils.date_spine() # Generate date dimension
- dbt_utils.pivot() # Pivot rows to columns
- dbt_utils.unpivot() # Unpivot columns to rows
- dbt_utils.group_by() # Generate group by columns
- dbt_utils.union_relations() # Union tables with same schema
- dbt_utils.recency_test() # Freshness test in SQL
- package: calogica/dbt_expectations
version: ">=0.10.0"
tests:
- expect_table_row_count_to_be_between
- expect_column_values_to_be_between
- expect_column_distinct_count_to_be_between
- expect_column_median_to_be_between
- package: dbt-labs/codegen
version: ">=0.12.0"
macros:
- generate_source_yaml() # Auto-generate source definitions
- generate_base_model() # Generate staging model SQL
- generate_model_yaml() # Generate model YAML from compiled SQL
{# Incremental merge macro with delete+insert #}
{% macro incremental_merge_with_delete(source_table, target_table, unique_key, delete_condition) %}
{% if is_incremental() %}
DELETE FROM {{ target_table }}
WHERE {{ unique_key }} IN (
SELECT {{ unique_key }}
FROM {{ source_table }}
WHERE {{ delete_condition }}
);
{% endif %}
INSERT INTO {{ target_table }}
SELECT * FROM {{ source_table }}
{% if is_incremental() %}
WHERE {{ unique_key }} NOT IN (
SELECT {{ unique_key }} FROM {{ target_table }}
)
{% endif %}
{% endmacro %}
{# Cross-database date truncation macro #}
{% macro date_trunc(unit, date_col) %}
{% if target.type == 'snowflake' %}
DATE_TRUNC('{{ unit }}', {{ date_col }})
{% elif target.type == 'bigquery' %}
DATE_TRUNC({{ date_col }}, {{ unit }})
{% elif target.type == 'redshift' %}
DATE_TRUNC('{{ unit }}', {{ date_col }})
{% elif target.type == 'postgres' %}
DATE_TRUNC('{{ unit }}', {{ date_col }})
{% endif %}
{% endmacro %}
# .github/workflows/dbt_ci.yml
name: dbt CI/CD
on: [pull_request]
jobs:
dbt_ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.11" }
- name: Install dbt
run: pip install dbt-{{ target.type }}
- name: dbt deps
run: dbt deps --profiles-dir .
- name: dbt debug
run: dbt debug --profiles-dir .
- name: dbt build --select state:modified+
run: dbt build --select state:modified+ --profiles-dir .
- name: dbt docs generate
run: dbt docs generate --profiles-dir .
- name: Upload docs
uses: actions/upload-artifact@v4
with: { name: docs, path: target/ }
Data size and update pattern?
├── Small (< 1M rows), rarely changes → View or Ephemeral
├── Medium (1M-100M), daily updates → Table (full refresh)
├── Large (100M+), append-only → Incremental (insert-only)
├── Large (100M+), updates/upserts → Incremental (merge)
├── Very large (1B+), time-series → Incremental (insert+partition)
└── Need sub-second query performance
├── Pre-aggregated results → Materialized view
└── Aggregated metrics → Incremental + summary table
# models/marts/python/customer_segments.py
import pandas as pd
from sklearn.cluster import KMeans
def model(dbt, session):
# Reference dbt model
customer_features_df = dbt.ref("int_customer_features").to_pandas()
# Apply clustering logic
features = customer_features_df[["recency", "frequency", "monetary"]]
kmeans = KMeans(n_clusters=5, random_state=42)
customer_features_df["segment"] = kmeans.fit_predict(features)
return customer_features_df
What are we validating?
├── Data integrity
│ ├── Primary key uniqueness → unique + not_null test
│ └── Foreign key validity → relationships test
├── Data quality
│ ├── Column values → accepted_values, range check
│ ├── Distribution → dbt_expectations distribution tests
│ └── Freshness → source freshness threshold
├── Business logic
│ ├── Row count consistency → dbt_utils.equal_rowcount
│ ├── Cardinality rules → cardinality_equality test
│ └── Cross-model consistency → custom assertions
└── Performance
├── Query runtime → dbt query-comment + monitor
└── Model complexity → model governance check
Source data characteristics?
├── Append-only (logs, events)
│ └── incremental_strategy: append
├── Updates on unique key (CDC, transactional)
│ └── incremental_strategy: merge
├── Deletes + inserts (daily snapshots)
│ └── incremental_strategy: delete+insert
├── Micro-batch (time-windowed)
│ └── incremental_strategy: insert_overwrite
└── Need point-in-time accuracy
└── Use snapshot strategy (scd_type: 2)
Analytics Engineering Stack
├── Transformation tool?
│ ├── dbt (SQL-first) → dbt Core / dbt Cloud
│ ├── Python-heavy → SQLMesh / Dataform
│ └── Multi-language → Dagster + dbt
├── Warehouse target?
│ ├── Snowflake → dbt-snowflake adapter (native features)
│ ├── BigQuery → dbt-bigquery (partitioning, clustering)
│ └── DuckDB → dbt-duckdb (local development)
├── Data modeling approach?
│ ├── Kimball → Star schema (facts + dimensions)
│ └── Data Vault → Hubs, links, satellites
└── CI/CD for data?
├── Yes → dbt CI with GitHub Actions + slim CI
└── No → Manual dbt run (not recommended)
Decision criteria: Evaluate team SQL vs Python skills, warehouse platform, modeling maturity, and CI requirements.
-- analytics_engineering/tests/generic/assert_valid_email.sql
{% test assert_valid_email(model, column_name) %}
SELECT {{ column_name }}
FROM {{ model }}
WHERE {{ column_name }} IS NOT NULL
AND {{ column_name }} !~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}#x27;
{% endtest %}
-- analytics_engineering/models/marts/dim_customer.sql
{{
config(
materialized='incremental',
unique_key='customer_key',
on_schema_change='append_new_columns',
incremental_strategy='merge',
)
}}
SELECT
customer_id,
customer_name,
email,
first_order_date,
lifetime_value,
updated_at
FROM {{ ref('stg_customers') }}
{% if is_incremental() %}
WHERE updated_at > (SELECT max(updated_at) FROM {{ this }})
{% endif %}
dbt build --select state:modified+ on PR for slim CI; fail on test failures.packages.yml; use semantic versioning.| Anti-Pattern | Consequence | Solution |
|---|---|---|
| dbt models without tests | Undetected quality issues | Test every model with generic + singular tests |
| No source freshness checks | Stale data propagated | Configure source freshness for all sources |
| Manual dbt run in production | Inconsistent state, no audit | CI/CD for all production runs |
| Single monolithic dbt project | Long run times, tight coupling | Split into domain-specific sub-projects |
| Ignoring dbt performance | Full refresh on every run | Use incremental models for large tables |
unique_key for merge strategy.dbt build --select state:modified+ to build only changed models + downstream.{{ ref() }} instead of raw table references for proper dependency resolution.cluster_by) with common query filter columns.data-science-statistical-analysis for analytical statistical methods
data-science-experimentation for experiment metric pipelines
data-quality for data quality testing and monitoring