Data Mart

A Data Mart is a subject-oriented analytical data store designed to support the reporting, analytics, and decision-making needs of a specific business function, department, domain, or analytical workload.

For example:

  • Sales Data Mart
  • Finance Data Mart
  • Customer Data Mart
  • Marketing Data Mart
  • Supply Chain Data Mart
  • HR Data Mart
Enterprise Data Warehouse / Lakehouse
企业中央数据平台
          |
          |---------------- Sales Data Mart
          |                  销售数据集市
          |
          |---------------- Finance Data Mart
          |                  财务数据集市
          |
          |---------------- Customer Data Mart
          |                  客户数据集市
          |
          |---------------- Marketing Data Mart
                             市场数据集市

A Data Mart typically contains curated, integrated, business-friendly data optimized for analytical queries rather than operational transactions.

What data marts actually address

What data marts actually address is: How do we turn enterprise data into a business-consumable analytical model?

The Real Value of a Data Mart

  • Business Simplification 业务简化
  • Consistent Business Definitions 统一业务定义
  • Performance 查询性能
  • Security 安全
  • Self-Service Analytics 自助分析

Data Mart vs Data Warehouse

  • Scope and Scale / 范围与规模
    • DWH: Centralizes cross-functional data across the entire enterprise. / 汇集整个企业跨部门的全局数据。
    • DM: Isolate highly specific data for teams like sales, marketing, or finance. / 仅隔离出销售、市场或财务等特定团队所需的局部数据。
  • Structural Architecture / 架构关系
    • Top-down (Inmon): The DWH is built first as a central repository, and Data Marts are extracted from it. / 自上而下架构: 先建立中央数仓,再从中抽取并生成各个数据集市。
    • Bottom-up (Kimball): Independent Data Marts are built first for business units, then integrated to form the DWH. / 自下而上架构: 先为各业务单元建立独立的数据集市,最终组合在一起构成全局数仓。
  • Speed and Performance / 速度与性能
    • DWH: Handles massive, complex analytical queries across different business domains, which can be slower. / 处理跨领域的海量复杂分析,查询可能较慢。
    • DM: Offers much faster query responses because it scans smaller, curated datasets. / 因为只扫描较小的、精选的数据集,所以查询响应速度极快。
Feature / 特性Data Warehouse (DWH) / 数据仓库Data Mart (DM) / 数据集市
Data Scope / 数据范围Enterprise-wide, cross-functional data / 汇集全企业、跨功能数据Single subject or specific department / 单一主题或特定部门
Data Sources / 数据来源Multiple operational systems and external feeds / 多个业务系统和外部数据源Mostly derived from the central warehouse / 大多衍生自中央数仓
Size / 数据容量Typically hundreds of gigabytes to petabytes / 通常为数百 GB 到 PB 级Usually less than 100 gigabytes / 通常小于 100 GB
Implementation / 实施周期Months to years to fully deploy / 全面部署需要数月到数年Days to weeks for a targeted setup / 针对性搭建仅需数天到数周
Primary Users / 主要用户Data scientists, enterprise analysts / 数据科学家、企业级分析师Department managers, local teams / 部门经理、业务团队

The Complete Data Mart Lifecycle

Business Requirements
        |
        v
Identify Business Process
        |
        v
Identify Grain
        |
        v
Identify Dimensions
        |
        v
Identify Facts
        |
        v
Source-to-Target Mapping
        |
        v
ETL / ELT
        |
        v
Data Quality
        |
        v
Data Mart
        |
        v
Semantic Layer
        |
        v
Power BI / Reporting

Where is Data Mart in Lakehouse

              Azure
                |
       +--------+---------+
       |                  |
     CRM                ERP
       |                  |
       +--------+---------+
                |
              Bronze
                |
              Silver
                |
              Gold
                |
      +---------+---------+
      |         |         |
      v         v         v
   Sales      Finance   Customer
   Mart        Mart       Mart
      |         |         |
      +---------+---------+
                |
             Power BI

The complete implementation of a data mart

assuming, we have those in Silver:

  • silver.orders
  • silver.order_items
  • silver.customers
  • silver.products

We are creating Sales Data Mart

Step 1 — Dimension

Dim Customer

-- ============================================================
-- PURPOSE:
--   Build the Customer Dimension for the Sales Data Mart.
--
-- WHY:
--   Fact_Sales will reference customer_key instead of storing
--   all customer descriptive attributes repeatedly.
-- ============================================================

CREATE TABLE gold.dim_customer
USING DELTA
AS
SELECT
    -- --------------------------------------------------------
    -- Surrogate Key
    -- --------------------------------------------------------
    -- A surrogate key is the warehouse/Data Mart key used
    -- internally by the dimensional model.
    -- --------------------------------------------------------
    monotonically_increasing_id() AS customer_key,

    -- --------------------------------------------------------
    -- Business Key
    -- --------------------------------------------------------
    -- This is the identifier coming from the source system.
    -- Example: CRM customer ID.
    -- --------------------------------------------------------
    customer_id,

    -- --------------------------------------------------------
    -- Descriptive Attributes
    -- These attributes describe the customer.
    -- --------------------------------------------------------
    customer_name,
    city,
    province,
    customer_segment

FROM silver.customers;

Product Dimension

-- ============================================================
-- PURPOSE:
--   Create the Product Dimension.
--
-- BUSINESS PURPOSE:
--   Allow analysts to slice sales by product, category,
--   brand, etc.
-- ============================================================

CREATE TABLE gold.dim_product
USING DELTA
AS
SELECT
    -- Internal surrogate key used by the Data Mart
    monotonically_increasing_id() AS product_key,

    -- Source-system business key
    product_id,

    -- Business descriptive attributes
    product_name,
    category,
    brand

FROM silver.products;

Date Dimension

-- ============================================================
-- PURPOSE:
--   Create a reusable Date Dimension.
--
-- WHY:
--   Business users frequently analyze data by:
--       Year
--       Quarter
--       Month
--       Week
--       Day
--
--   Instead of repeatedly calculating these values from the
--   transaction timestamp, we centralize the business calendar.
-- ============================================================

CREATE TABLE gold.dim_date
USING DELTA
AS
SELECT
    date,

    -- Calendar attributes
    year(date)    AS year,
    quarter(date) AS quarter,
    month(date)   AS month,
    day(date)     AS day,

    -- Useful reporting attributes
    dayofweek(date) AS day_of_week,
    date_format(date, 'MMMM') AS month_name

FROM (
    -- Generate a calendar covering the required business period.
    SELECT explode(
        sequence(
            DATE '2020-01-01',
            DATE '2030-12-31',
            INTERVAL 1 DAY
        )
    ) AS date
);

Step 2 — Fact Sales

Fact_Sales

-- ============================================================
-- PURPOSE:
--   Build the Sales Fact Table.
--
-- GRAIN:
--   One row = one order line item.
--
-- THIS IS CRITICAL.
--   We must define the grain BEFORE loading the fact table.
-- ============================================================

CREATE TABLE gold.fact_sales
USING DELTA
AS
SELECT

    -- ========================================================
    -- Dimension Foreign Keys
    -- ========================================================

    d.date_key,

    c.customer_key,

    p.product_key,

    -- ========================================================
    -- Degenerate / Business Identifiers
    -- ========================================================

    oi.order_id,

    -- ========================================================
    -- Measures
    -- ========================================================

    oi.quantity,

    oi.sales_amount,

    oi.discount_amount,

    oi.cost_amount,

    -- Profit is derived from business measures.
    -- ========================================================
    oi.sales_amount
        - oi.discount_amount
        - oi.cost_amount AS profit_amount

FROM silver.order_items oi

-- ============================================================
-- Join Customer Dimension
-- ============================================================
JOIN gold.dim_customer c
    ON oi.customer_id = c.customer_id

-- ============================================================
-- Join Product Dimension
-- ============================================================
JOIN gold.dim_product p
    ON oi.product_id = p.product_id

-- ============================================================
-- Join Date Dimension
-- ============================================================
JOIN gold.dim_date d
    ON CAST(oi.order_date AS DATE) = d.date;
                     dim_customer
                          |
                          |
                          |
dim_date ---------- fact_sales ---------- dim_product
                          |
                          |
                       dim_store

What was revenue by customer segment and month?

SELECT
    d.year,
    d.month,
    c.customer_segment,
    SUM(f.sales_amount) AS revenue
FROM gold.fact_sales f

JOIN gold.dim_customer c
    ON f.customer_key = c.customer_key

JOIN gold.dim_date d
    ON f.date_key = d.date_key

GROUP BY
    d.year,
    d.month,
    c.customer_segment

ORDER BY
    d.year,
    d.month,
    c.customer_segment;

Key Takeaways

Data Mart: A subject-oriented analytical data store designed for a specific business domain or analytical purpose.
面向特定业务领域、部门或分析需求的数据分析存储层。

ConceptWhat is it?Main Purpose
Data LakeLarge-scale flexible data repositoryStore diverse data
Data WarehouseIntegrated analytical platformEnterprise analytics
Data MartDomain-oriented analytical storeBusiness-domain analytics
LakehouseArchitecture combining lake + warehouse capabilitiesUnified data platform

For easy remember:

Data Lake: Store Data

  • Raw
  • Flexible
  • Large scale
  • Structured + Semi-structured + Unstructured

Data Warehouse: Integrate and analyze enterprise data

  • Enterprise-wide
  • Integrated
  • Structured
  • Governed
  • Historical
  • Analytics

Data Mart: Serve a specific business domain

  • Sales
  • Finance
  • Customer
  • Risk
  • Marketing
  • HR

Lakehouse: Unify Data Lake + Data Warehouse capabilities

Scalable storage
+
ACID
+
Governance
+
SQL Analytics
+
BI
+
Data Engineering
+
ML / AI

Data Lake / Warehouse / Lakehouse describe data-platform architecture;
Data Mart describes a business-oriented analytical data product or store.

Kimball Dimensional Modeling

Data Modeling include:

  • Conceptual Modeling
  • Logical Modeling
  • Physical Modeling
  • Operational Data Modeling
  • Relational Modeling
  • Data Vault
  • Dimensional Modeling
    e.g. Kimball dimensional modeling
  • Other Modeling Approaches

Dimensional Modeling is a data modeling technique designed primarily for analytical workloads.

It organizes data around:

  • Facts — measurable business events 可以度量的业务事件
  • Dimensions — descriptive business context 描述业务上下文的信息

Kimball Dimensional Modeling

Kimball Dimensional Modeling is an approach to designing analytical data warehouses using dimensional models, centered around business processes, facts, dimensions, conformed dimensions, and a bus architecture.

Kimball Dimensional Modeling belongs to Dimmensional Modeling.

The Core Philosophy of Kimball:
Start with the business process, not the database tables.

Important concept of Kimball’s dimensional modeling

Business Process

A Business Process is a business activity that an organization performs and wants to measure, analyze, and improve.
企业正在执行的一类业务活动,而且企业希望对这类活动进行度量、分析和改进. e.g.

  • 销售 Sales
  • 订单履行 Order Fulfillment
  • 库存 Inventory
  • 支付 Payments
  • 退货 Returns
  • 保险理赔 Claims
  • 医院入院 Admissions
  • 贷款申请 Loan Applications
  • 客户服务 Customer Service

Kimball dimensional modeling starts with the business process.

Typical examples of Business Processes

Retail:

  • Sales
  • Inventory
  • Returns
  • Payments
  • Shipping

Banking:

  • Account Opening
  • Transactions
  • Payments
  • Loans
  • Credit Card Transactions
  • Fraud Detection

Government

  • Application
  • Case Processing
  • Permit Issuance
  • Payment
  • Inspection
  • Appeal

Kimball Dimensional Design — 4 Steps

The four critical steps of the Kimball lifecycle / dimensional modeling methodology are:

  1. Select the Business Process
  2. Declare the Grain
  3. Identify the Dimensions
  4. Identify the Facts

An Example: “We want to analyze credit card transactions.”

Do not create tables now.

Step 1: Select the Business Process

What is the Business Process? Credit Card Transaction

What is the Business Event? A cardholder makes a transaction
at a merchant.

Step 2: Declare the Grain

What is the Grain? One row = one credit card transaction

Step 3: Identify the Dimensions

What Dimensions?

  • Customer
  • Card
  • Merchant
  • Date
  • Time
  • Location
  • Transaction Type

Step 4: Identify the Facts

What Facts?

  • Transaction Amount
  • Fee Amount
  • Tax Amount
  • Reward Points

Finally:

                  Dim Customer
                       |
                       |
Dim Card ------- Fact Transaction ------ Dim Merchant
                       |
                       |
                    Dim Date
                       |
                       |
                    Dim Time

This is Kimball’s thought.

Implementation – Initially Physical Model

Assuming, I have decided:
Grain = one row per sales order line

#  Fact
CREATE TABLE fact_sales (
    sales_date_key       INT,
    customer_key         BIGINT,
    product_key          BIGINT,
    store_key            BIGINT,

    order_number         STRING,

    quantity             DECIMAL(18,2),
    unit_price            DECIMAL(18,2),
    discount_amount       DECIMAL(18,2),
    sales_amount          DECIMAL(18,2),
    cost_amount           DECIMAL(18,2)
);



#  Dimensions:
CREATE TABLE dim_customer (
    customer_key BIGINT,
    customer_id  STRING,
    customer_name STRING,
    province STRING,
    customer_segment STRING
);

CREATE TABLE dim_product (
    product_key BIGINT,
    product_id STRING,
    product_name STRING,
    category STRING,
    brand STRING
);

CREATE TABLE dim_date (
    date_key INT,
    calendar_date DATE,
    year INT,
    quarter INT,
    month INT,
    month_name STRING,
    day_of_week STRING
);

Grain:Fact Table

The grain defines exactly what one row in a fact table represents.
Grain 定义 Fact Table 中“一行数据到底代表什么业务事件”。

One row = one sales transaction
一行 = 一笔销售交易

One row = one sales transaction
一行 = 一笔销售交易

One row = one order line
一行 = 一个订单明细

Grain is the semantic contract of the fact table.

Three common fact grains in Kimball

In data warehousing, these three grains are formally known as:

  1. Transaction Fact grain (事务粒度)
  2. Periodic snapshot Fact grain (周期快照粒度)
  3. Accumulating snapshot Fact grain (累积快照粒度)
Fact TypeGrain核心问题
Transaction FactOne business event
一次业务事件
What happened?
发生了什么?
Periodic SnapshotOne entity/process at a periodic point
某个周期时点的状态
What was the state?
当时状态如何?
Accumulating SnapshotOne process lifecycle
一个业务流程生命周期
How did the process progress?
流程进行到哪里?

Transaction Fact Grain

One row represents one business transaction/event.

e.g. One row = one order line

DateCustomerProductStoreQtySales
Sep 13C001P001S00111200
Sep 13C001P002S0012500
Sep 13C001P003S001150

Periodic snapshot Fact grain

A row represents the state of a business process at a regular point in time.
一行代表某个业务对象/流程在一个固定周期时间点的状态。

e.g. Account Balance Snapshot
One row = Customer Account + Day

DateAccountBalance
Sep 11A00110,000
Sep 12A0019,500
Sep 13A00111,000

Accumulating snapshot Fact grain

A single row represents the entire lifecycle of a process or a specific entity that moves through multiple, predictable milestones.

e.g. Order Fulfillment

Order Created
↓
Payment Approved
↓
Warehouse Processing
↓
Shipped
↓
Delivered

We can represent the entire lifecycle of an order in one row.

OrderOrder DatePayment DateShip DateDelivery Date
10001Sep 10Sep 10Sep 11Sep 13

Grain Determines Whether a Fact Is Valid

A fact is only meaningful if it is measured at the same grain as the fact table.
一个 Fact 只有在与 Fact Table 的 Grain 相匹配时,才是有意义、可以正确分析的。

Suppose we define:

Grain: One row represents one Order Line.

That means every row in the fact table represents exactly:

One product on one order

OrderProductQuantitySales Amount
O1001iPhone1$1,200
O1001AirPods2$500
O1002MacBook1$2,000

A error fact example.

OrderProductSales AmountOrder Total
O1001iPhone1,2001,700
O1001AirPods5001,700

there is issue on the column “Order Total”
把 $1,700 放进一个 Order-Line Grain 的 Fact Table,并让它看起来像每一行的可加 Fact,是错误的设计。 我们的 Fact Grain 是 “One row represents one Order Line.” 一行一个order 的 “行” – order 上的一行。

Order Total O1001 这份order的 合计金额, 是 “Order Grain” – 一份order的. 放在目前的Fact 上就不对。

如果一定要使用 “Order Total ”, 那就再叫另外一个Fact_order,

Grain:One row per Order

OrderCustomerOrder TotalShipping Cost
O1001C001170020
O1002C002200030

Grain Determines Dimension Context

Kimball-style terminology: The grain defines not only what the fact represents, but also which dimensions can validly describe the row.

Dimensions

A Dimension is a business-oriented structure that provides the descriptive context used to analyze facts.
用于描述和分析 Fact 的业务分析结构。

A Very Important Kimball Principle

Kimball Principle: Dimensions should be understandable to business users.

Data Modeling

Data Modeling is the process of deciding how business data should be

  • structured,
  • organized,
  • related,
  • represented

so that people and computer systems can use it correctly.

In simple terms: Data Modeling = deciding what data we have, what each piece of data means, how different data is related, and how we should organize it.

Data Modeling include:

  • Conceptual Modeling
  • Logical Modeling
  • Physical Modeling
  • Operational Data Modeling
  • Relational Modeling
  • Data Vault
  • Dimensional Modeling
    e.g. Kimball dimensional modeling
  • Other Modeling Approaches

What is Data Modeling actually DOING?

We take the real business world and translate it into a structured data representation that a computer can store, query, analyze, and maintain.

Data Modeling is about MEANING, not just tables.

The basic building blocks of Data Modeling

English中文
Entity实体: 我们要管理的“东西”

可识别 + 业务相关 + 可以被描述
An Entity is a distinct business object or concept that we want to represent in data.

Identifiable + Relevant + Describable
Attribute属性: 描述这个东西的信息An Attribute describes a property or characteristic of an entity.
Relationship关系: 东西和东西之间怎么关联
Cardinality基数 / 数量关系

一个对多少个
Cardinality specifies how many instances of one Entity can be associated with an instance of another Entity.
1:1, 1:N, N:1, N:N
Key键Cardinality specifies how many instances of one Entity can be associated with an instance of another Entity.
simple, “Which exact record is this?”

A Primary Key is the chosen attribute or combination of attributes that uniquely identifies each row in a table.
A Foreign Key is an attribute in one entity/table that references the key of another entity/table.
Constraint约束

The three levels of Data Modeling

Conceptual Model

Conceptual Model is a high-level representation of the major business entities and their relationships.

Simply, what business things exist? 业务上有什么东西?

Logical Model

The Logical Data Model defines the detailed structure of the data, including entities, attributes, relationships, keys, and business rules, without depending on a specific database technology.

Simply, how should the business data be logically organized?

Physical Model

The Physical Data Model describes how the logical model will actually be implemented in a specific database, data warehouse, lakehouse, or other technology.

Simply, how will we actually store and implement the data?

ModelQuestion中文
ConceptualWhat?有什么业务东西?
LogicalHow is it organized?数据逻辑上怎么组织?
PhysicalHow is it implemented?技术上怎么真正实现?

What is Normalization?

Normalization is a data modeling technique used to organize data so that:

  • unnecessary duplication is reduced
  • data dependencies are correctly represented
  • update anomalies are minimized
  • data integrity is improved

Why do we normalize data?

Normalization organizes data around business entities and dependencies. It reduces unnecessary redundancy and prevents update, insert, and delete anomalies while improving data integrity and maintainability.
Normalization 是根据业务实体和数据依赖关系来组织数据,减少不必要的数据冗余,避免 Update、Insert 和 Delete Anomalies,同时提高数据完整性和可维护性。

First Normal Form — 1NF

A table is in 1NF when each attribute contains atomic values, meaning each cell represents a single value rather than a repeating group or list.
每个 Cell 应该保存一个 Atomic Value(原子值),而不是一个列表或重复组。

Second Normal Form — 2NF

A table is in 2NF when:

  1. It is already in 1NF 首先必须满足 1NF
  2. Every non-key attribute depends on the whole primary key, not only part of a composite key. 所有非 Key 属性必须依赖于整个 Primary Key, 不能只依赖 Composite Key 的一部分

Third Normal Form — 3NF

A table is in 3NF when:

  1. It is in 2NF
  2. Non-key attributes depend on the key, the whole key, and nothing but the key.

Grain

粒度

The grain defines exactly what one row in a fact table represents.
Grain 定义 Fact Table 中“一行数据到底代表什么业务事件”。

Key Takeaways

  1. Data Modeling translates the real business world into structured data.
    是把现实业务世界转换成结构化的数据。
  2. An Entity represents a business object or concept.
    表示一个业务对象或业务概念。
  3. An Attribute describes an Entity.
    描述 Entity 的特征
  4. A Relationship describes how Entities are connected.
    描述不同 Entity 之间如何关联。
  5. Cardinality describes how many instances of one Entity can relate to another.
    描述两个 Entity 之间“一对一、一对多、多对多”的数量关系。

Data mesh

Data mesh is a decentralized data architecture and organizational model that shifts data ownership from a single central IT team to individual business domains.

Its core idea is: Data should be owned and managed by the business domains that understand that data best, while still following common enterprise governance standards.

Instead of one central data team owning everything, different business domains become responsible for their own data products.

Enterprise
│
├── Customer Domain
│   └── Customer Data Product
│
├── Finance Domain
│   └── Finance Data Product
│
├── Risk Domain
│   └── Risk Data Product
│
├── HR Domain
│   └── Employee Data Product
│
└── Operations Domain
    └── Operations Data Product

Data Mesh, on the other hand, becomes: Domain owns the data, Enterprise governs the data.

Finance Domain → looks after Finance Data
HR Domain → looks after HR Data
Risk Domain → looks after Risk Data
Customer Domain → looks after Customer Data

What is Data Mesh trying to address?

  • Domain Ownership
    Data is owned by the business domains.
  • Data as a Product
    Data must be treated like a product.
  • Self-Serve Data Platform
    The enterprise provides a centralized platform enabling domains to autonomously publish and govern their data.
  • Federated Computational Governance
    The enterprise continues to define standardized rules.
    • Security
    • Privacy
    • Governance
    • Compliance
    • Data Quality
    • Metadata
    • Lineage

What is Domain-Driven Modeling?

Domain-Driven Modeling means: Designing data models around the business domains, business concepts, business processes, and business rules rather than starting from source-system tables.

Domain vs Canonical Model

Canonical Model ≠ Data Mesh

Data Mesh –>Reorganize data ownership, data products, the platform, and governance.

                 Enterprise
                     │
             Data Mesh Governance
                     │
        ┌────────────┼────────────┐
        ↓            ↓            ↓
    Customer       Finance       Risk
     Domain         Domain       Domain
        │            │            │
     Canonical    Canonical    Canonical
      Model         Model        Model
        │            │            │
    Data Product  Data Product  Data Product

Data Mesh targets a different set of challenges: data is owned by the business domains, it must be treated like a product, and the enterprise provides a unified self-serve platform. Ultimately, it requires reorganizing data ownership, data products, the platform, and governance.

What exactly are we modeling in Domain-Driven Design?

Business Domain

First, determine: What business area are we modeling?

  • Customer
  • Payment
  • Risk
  • Mortgage
  • Finance

Business Capability

Within a domain, we can further examine business capabilities

Customer Domain
│
├── Customer Onboarding
├── Customer Identification
├── Customer Profile Management
├── Customer Relationship Management
└── Customer Communication

Capability indicates: What the business domain can do.
Capability 表示:这个业务领域能够做什么。

Business Concept

Then, identify the truly critical business concepts within the domain.
然后识别 Domain 中真正重要的业务概念。

# Customer Domain:
Customer
Customer Profile
Customer Relationship
Customer Address
Customer Contact

# Payment Domain:
Payment
Payment Instruction
Payment Method
Payment Transaction
Payment Status

Business Event

Taking it a step further: What events occur within the domain?

e.g.

  • CustomerCreated
  • CustomerUpdated
  • CustomerAddressChanged
  • PaymentInitiated
  • PaymentCompleted
  • PaymentFailed

In Domain-Driven Design (DDD), things that “happen” are specifically called “Domain Events.”

Using the word “events” makes your phrasing sound highly sophisticated and immediately signals the right architectural concept to other engineers.

Business Rule

Domain has business rules. e.g.

Payment amount > $10,000
↓
Additional approval required

Data Entity

Finally, data modeling

Customer
Account
Payment
Address
Transaction

THen define

Attributes
Keys
Relationships
Cardinality
Constraints
History

Therefore, the overall process is as follows:

Business Domain
       ↓
Business Capability
       ↓
Business Concept
       ↓
Business Event
       ↓
Business Rule
       ↓
Domain Entity
       ↓
Data Model
       ↓
Data Product

Complete example

Step 1 — Identify Domain

Customer Domain: Manage customer identity, profile and relationship information.

Step 2 — Identify Business Concepts

Customer
Customer Profile
Customer Address
Customer Contact
Customer Relationship

Step 3 — Identify Business Events

CustomerCreated
CustomerUpdated
CustomerAddressChanged
CustomerStatusChanged

Step 4 — Identify Business Rules

e.g. Customer must have a unique enterprise customer ID.

Customer status must be one of:

  • ACTIVE
  • INACTIVE
  • SUSPENDED
  • CLOSED

Step 5 — Build Domain Model

Customer
│
├── Customer Profile
│
├── Customer Address
│
├── Customer Contact
│
└── Customer Relationship

Step 6 — Map Source Systems

CRM
   │
   ├── CRM_CUSTOMER
   └── CRM_CONTACT
             │
             ↓
Core Banking ─────→ Customer Domain
   │
   └── CUSTOMER
             │
             ↓
Mortgage
   │
   └── BORROWER

Step 7 — Canonical Model

Customer
------------------------
customer_id
customer_type
first_name
last_name
date_of_birth
status
created_date
updated_date

Step 8 — Data Product

Customer Domain provides “Customer Data Product”.

e.g. customer.gold_customer. it should has

  • Owner
  • Schema
  • Description
  • Data Quality
  • SLA
  • Security
  • Lineage
  • Documentation
  • Access Policy

As a result, the downstream Risk team does not need direct access to:

  • CRM
  • Core Banking
  • Mortgage

Instead, they consume: Customer Data Product

How to implement in Databricks

                    Enterprise Data Mesh
                            │
              Federated Governance
                            │
        ┌───────────────────┼───────────────────┐
        ↓                   ↓                   ↓
 Customer Domain       Finance Domain       Risk Domain
        │                   │                   │
        ↓                   ↓                   ↓
 Unity Catalog         Unity Catalog        Unity Catalog
        │                   │                   │
        ↓                   ↓                   ↓
 Delta Tables          Delta Tables         Delta Tables
        │                   │                   │
        ↓                   ↓                   ↓
 Data Products         Data Products        Data Products

Catalog / Schema designing

e.g.

customer_catalog
│
├── bronze
├── silver
└── gold

Do not think “One Domain = One Catalog”,
No, implementation choice, it is NOT data Mesh define

Domain-owned tables

-- ============================================================
-- PURPOSE:
-- Create the Customer domain's curated customer entity.
--
-- KEY IDEA:
-- The Customer domain owns the business meaning and quality
-- of this dataset.
-- ============================================================

CREATE TABLE customer_catalog.gold.customer
(
    -- Enterprise-wide business identifier.
    customer_id STRING NOT NULL,

    -- Business classification of the customer.
    customer_type STRING,

    -- Standardized customer name.
    first_name STRING,
    last_name STRING,

    -- Standardized date of birth.
    date_of_birth DATE,

    -- Controlled business status.
    status STRING,

    -- Audit columns.
    created_date TIMESTAMP,
    updated_date TIMESTAMP
)
USING DELTA;

Key Takeaways

Data Mesh is primarily about how an enterprise organizes ownership, products, platforms, and governance around data domains.

Domain: Business responsibility boundary

Domain-Driven Modeling: Business first –> Data model second

Canonical Model: Standardized enterprise representation of data

Data Product: A Data Product is not simply a Delta table.

Data Vault

What is Data Vault?

Data Vault is a data warehouse modeling methodology designed to build an enterprise data platform that is:

  • scalable
  • auditable
  • historically accurate
  • adaptable to changing source systems
  • able to integrate data from many different sources

The central idea is: Separate business identity, relationships, and descriptive history.

Data Vault mainly does this through three building blocks:

Hub + Link + Satellite

You will often see this called: Hubs, Links, and Satellites — HLS

Hub: Represents the primary business objects.
Link: Defines the associations between business objects.
Satellite: Stores descriptive attributes and records historical changes to those attributes.

You can think this way, a Bank, it has many source systems

CRM
│
├── Customer
│
Core Banking
│
├── Customer
├── Account
│
Credit System
│
├── Customer
├── Loan
│
Credit Card System
│
├── Customer
├── Card
│
Mobile Banking
│
├── Customer
└── Transaction

A customer has:

CRM            → C123
Core Banking   → 100023
Credit System  → CU-789
Card System    → 998877

Assuming Source systems changeing

# Now

Customer
----------------
Customer_ID
Name
Email
Phone

# tomorrow changing to
Customer
----------------
Customer_ID
First_Name
Last_Name
Email
Mobile_Phone

Data Vault will sperate Business Identity and Descriptive Attributes

Hub_Customer, looks after “Customer Business Key”

Satellite_Customer: looks after

“Name
Email
Phone
Address
Status
… “

Once source add a new attribute – “Preferred_Language”, System only need change Satellite.

Assuming, Historical data tracking

assuming,

2024:
Customer = John
City = Toronto

2025:
Customer = John
City = Vancouver

2026:
Customer = John
City = Calgary

under this scenario, enterprice wants to know:
“When did John live in Toronto? When did he move to Vancouver, and when did he move to Calgary?”

Data Vault does “Don’t overwrite histrory unnecessarily“, keep all history change

Hub Customer
     │
     ▼
Satellite Customer
     
Customer_Key | City       | Load_Date
-------------|------------|-----------
C10001       | Toronto    | 2024-01-01
C10001       | Vancouver  | 2025-03-15
C10001       | Calgary    | 2026-02-10

Auditability

Enterprice offen asks where does this data come?
e.g. Customer Email = abc@gmail.com

Data Vault highly emphasizes:

  • Source System
  • Load Date
  • Record Source
  • Business Key
  • Hash Key
  • Hash Diff

so we create

Source System
↓
Raw Data
↓
Data Vault
↓
Business Data

to keep data lineage / history

The three core components of Data Vault

Hub – Link – Satellite

Hub represents a unique business concept or business key. It answers “Who is this business entity?”

Link represents a business relationship between Hubs. It is Business relationship

Customer owns Account
Customer applies for Loan
Customer holds Credit Card
Employee works for Branch
Supplier provides Product

Satellite stores descriptive attributes and their historical changes. It descripts Hub or Link and information lineages, history change.

example: customer

Data Vault will ask:
What is this entity? —- Hub

Customer ID = C10001

How does it relate to other objects? —- Link

Link Customer-Account
Customer C10001
|
| owns
|
Account A90001

What attributes does this Customer have? —- Satellite

Customer C10001

Name = John Smith
Email = john@gmail.com
City = Toronto
Status = Active

             ┌──────────────┐
             │    HUB       │
             │              │
             │ WHO ARE YOU? │
             └──────┬───────┘
                    │
                    │ relationship
                    ▼
             ┌──────────────┐
             │    LINK      │
             │              │
             │ WHO IS       │
             │ RELATED TO   │
             │ WHOM?        │
             └──────┬───────┘
                    │
                    ▼
             ┌──────────────┐
             │  SATELLITE   │
             │              │
             │ WHAT DO WE   │
             │ KNOW ABOUT   │
             │ IT?          │
             └──────────────┘

A complete example

assuming:

Customer:
C001

Account:
A100

Customer open Account.

Hub Customer

Hub_Customer

Customer_HK | Customer_BK | Load_DTS  | Record_Source
-------------|-------------|-----------|--------------
...          | C001        | 2026-01-01| CRM

Hub Account

Hub_Account

Account_HK | Account_BK | Load_DTS  | Record_Source
-----------|------------|-----------|--------------
...        | A100       | 2026-01-01| CoreBanking

Link Customer Account

Link_Customer_Account

Customer_HK | Account_HK | Load_DTS  | Record_Source
------------|------------|-----------|--------------
...         | ...        | 2026-01-01| CoreBanking

Satellite Customer

Sat_Customer

Customer_HK
Name
Email
City
Status
Load_DTS
Record_Source
Hash_Diff

e.g.

C001 | John | john@gmail.com | Toronto | Active

then:

C001 | John | john@gmail.com | Vancouver | Active

we keep the histrory

Key Takeaways

A scalable, auditable, historical data modeling methodology for enterprise data integration.

ComponentEnglish中文人话
HubBusiness identity / key业务身份你是谁
LinkBusiness relationship业务关系你和谁有关系
SatelliteDescriptive attributes + history属性 + 历史关于你的信息

Hub tells us WHAT business entity we have, Link tells us HOW entities are related, and Satellite tells us WHAT we know about those entities over time.

Hub 告诉我们“业务对象是谁”,Link 告诉我们“对象之间是什么关系”,Satellite 告诉我们“关于这些对象知道什么,以及这些信息如何随时间变化”。

Canonical Model

1. What is Canonical Model?

A canonical model is a design pattern that uses a single, standardized data format to let different systems talk to each other without needing custom connections for every pair.

先用人话说, Canonical Model = 企业统一规定的一套“标准数据语言”。大家都必须按照同一套“词典 + 语法 + 数据结构”来描述同一个业务对象。

For example, a company has 10 data system, each system has “customer”. but the “customer” is named in different way in each data system.

SystemCustomer IDCustomer NamePhone
CRMcustomer_idcustomer_namephone
BankingCUST_NOCUST_NMMOBILE_NO
Insuranceclient_idfull_nametelephone
ERPBP_IDBP_NAMETEL_NO

Canonical Model means that all “Customer” will be uniformly defined in this way in the future in the company.

Customer
│
├── customer_id
├── first_name
├── last_name
├── date_of_birth
├── email
├── phone
└── address

CRM.customer_id → Canonical.Customer.customer_id

Bank.CUST_NO → Canonical.Customer.customer_id

Insurance.client_id → Canonical.Customer.customer_id

So, this is the core concept of Canonical. Reduce data integration complexity through a common enterprise representation.

2. What are included in Canonical Model

2.1 Business Entity

How many important business entity are there in a enterprice? for eaxample, Banking:

  • Customer
  • Account
  • Product
  • Transaction
  • Branch
  • Employee
  • Loan
  • Payment

Healthcare:

  • Patient
  • Provider
  • Hospital
  • Encounter
  • Diagnosis
  • Medication
  • LabResult
  • ClinicalDocument

These are Canonical Business Entities

2.2 Attributes

Each entity has its own attributes. for example,

customer, it may define:

  • customer_id
  • first_name
  • last_name
  • date_of_birth
  • email
  • phone
  • status

2.3 Relationships

Canonical Model has to define relationship between entity, e.g. a customer may has multiple account, so it is ” 1 … N “

Customer
│
├── Account 001
├── Account 002
└── Account 003

3. Data Type

Data types are another key component of the Canonical Model. For example, ‘Date of Birth’ must have a consistent data type across the system, rather than being defined as a Varchar one day and a Date type the next.

4. Business Meaning

Unique enterprise identifier representing a customer within the enterprise customer domain.

How does Canonical Model use in Lakehouse

                ┌──────────────┐
                │ CRM          │
                └──────┬───────┘
                       │
                ┌──────▼───────┐
                │ Banking      │
                └──────┬───────┘
                       │
                ┌──────▼───────┐
                │ ERP          │
                └──────┬───────┘
                       │
                       ▼
              ┌──────────────────┐
              │ Bronze           │
              │ Raw Source Data  │
              └────────┬─────────┘
                       │
                       ▼
              ┌──────────────────┐
              │ Standardization │
              │ + Mapping       │
              └────────┬─────────┘
                       │
                       ▼
              ┌──────────────────┐
              │ Canonical       │
              │ Customer        │
              └────────┬─────────┘
                       │
                       ▼
              ┌──────────────────┐
              │ Unified /        │
              │ Conformed Data   │
              └────────┬─────────┘
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
       Power BI       ML/AI       APIs

A complete example

Assuming, a enterprice has 3 system CRM, Banking and Insurance

CRM

CUST_ID
CUST_NAME
MOBILE_NO

Banking

CUSTOMER_NO
FULL_NAME
PHONE

Insurance

CLIENT_ID
NAME
TELEPHONE

Canonical:

Customer
├── customer_id
├── name
└── phone

Mapping:

CRM.CUST_ID    --->    Customer.customer_id

CRM.CUST_NAME  --->    Customer.name

CRM.MOBILE_NO  --->    Customer.phone

Bank:

Banking.CUSTOMER_NO
        ↓
Customer.customer_id

Insurance:

Insurance.CLIENT_ID
        ↓
Customer.customer_id

Implementation in Databricks Lakehouse

Assuming data looks this:

CUST_ID | CUST_NM       | MOBILE_NO
--------|---------------|------------
10001   | John Smith    | 416-111-1111
10002   | Mary Chen     | 416-222-2222

Bronze:

-- ============================================================
-- BRONZE LAYER
-- Purpose:
--   保留 CRM 原始数据。
--
-- Key point:
--   Bronze 不应该急着改变 Source System 的原始结构。
--   我们首先保证 source fidelity / traceability。
-- ============================================================

CREATE TABLE bronze.crm_customer
AS
SELECT
    *
FROM source.crm_customer;

Create Canonical Customer

Customer

-- ============================================================
-- SILVER / CANONICAL LAYER
--
-- Purpose:
--   将 CRM Source Model 转换成 Enterprise Canonical Model。
--
-- 这里最重要的工作不是简单 rename column。
-- 我们同时执行:
--
--   1. Schema standardization
--   2. Data type standardization
--   3. Business naming standardization
--   4. Data cleansing
--   5. Business rule application
-- ============================================================

CREATE OR REPLACE TABLE silver.canonical_customer AS

SELECT
    -- --------------------------------------------------------
    -- 将 CRM 的 CUST_ID 映射为企业统一的 customer_id。
    -- --------------------------------------------------------
    CAST(CUST_ID AS STRING) AS customer_id,

    -- --------------------------------------------------------
    -- 将 Source System 的 CUST_NM
    -- 转换成 Canonical Model 的 name。
    -- trim() 用于消除 source data 中多余空格。
    -- --------------------------------------------------------
    TRIM(CUST_NM) AS name,

    -- --------------------------------------------------------
    -- 统一电话号码格式。
    -- 实际企业项目中这里可能还会调用标准化规则。
    -- --------------------------------------------------------
    MOBILE_NO AS phone,

    -- --------------------------------------------------------
    -- 添加 source_system。
    -- 这个 metadata 非常重要:
    -- 后续可以追溯数据来自哪个系统。
    -- --------------------------------------------------------
    'CRM' AS source_system,

    -- --------------------------------------------------------
    -- 记录 ingestion / transformation 时间。
    -- 用于 lineage、audit 和 troubleshooting。
    -- --------------------------------------------------------
    current_timestamp() AS processed_at

FROM bronze.crm_customer;

result:
customer_id | name        | phone
------------|-------------|---------------
10001       | John Smith  | 416-111-1111
10002       | Mary Chen   | 416-222-2222

Banking

  • CUSTOMER_NO
  • FULL_NAME
  • PHONE
-- ============================================================
-- 将 Banking Source Model 转换为同一个 Canonical Model。
--
-- 注意:
-- CRM 和 Banking 的 Source Schema 完全不同。
-- 但是输出 Schema 必须遵循同一个 Canonical Contract。
-- ============================================================

SELECT
    CAST(CUSTOMER_NO AS STRING) AS customer_id,
    TRIM(FULL_NAME) AS name,
    PHONE AS phone,
    'BANKING' AS source_system,
    current_timestamp() AS processed_at
FROM bronze.banking_customer;

Unified Customer

-- ============================================================
-- UNIFIED CUSTOMER
--
-- Purpose:
--   将不同 source systems 的 canonical records
--   汇聚成企业统一 Customer view。
--
-- 注意:
--   Canonicalization != Entity Resolution
--
--   Canonicalization:
--       把结构统一。
--
--   Entity Resolution:
--       判断两个 records 是否代表同一个真实 Customer。
-- ============================================================

CREATE OR REPLACE TABLE gold.unified_customer AS

SELECT
    customer_id,
    name,
    phone
FROM silver.canonical_customer_crm

UNION ALL

SELECT
    customer_id,
    name,
    phone
FROM silver.canonical_customer_banking;

Usually, in actual enterprise deployments, this stage usually includes the following additions:

Identity Resolution
Deduplication
Survivorship Rules
Master Data
Golden Record

Key Takeaways

Canonical Model answers: “When different systems talk about the same business concept, what should that concept look like and mean inside the enterprise?”

要点ENCN
Canonical ModelStandardized enterprise representation of data企业统一的数据表示方式
核心目的Reduce integration complexity降低系统集成复杂度
核心思想Different sources → common representation不同 Source → 统一表示
Business EntityCustomer, Account, Product, etc.业务实体
AttributesStandardized fields and meanings标准化字段及业务含义
RelationshipsDefines relationships between entities定义实体之间关系
Business SemanticsDefines what each field actually means定义字段真正的业务含义
Source ModelRepresents one source system某个源系统自己的数据模型
Canonical ModelEnterprise-standard representation企业标准数据模型
Data UnificationCombines data into a consistent enterprise view将数据统一成企业级一致视图
Master DataIdentifies and manages trusted business entities管理可信的核心业务实体
Data ContractDefines producer/consumer data agreement定义生产者与消费者之间的数据契约
DatabricksCanonical can be implemented using Delta tables/views可用 Delta Table/View 等实现
Canonical ≠ UnificationStructure standardization is not identity resolution结构统一不等于实体统一
Canonical + MetadataMetadata explains meaning, ownership, lineage, etc.Metadata 解释含义、Owner、Lineage 等
Canonical + DQCanonical fields can have standardized quality rulesCanonical 字段可以有统一质量规则
Canonical + GovernanceStandard model enables consistent governance标准模型有利于统一治理

Logging in Azure Databricks with Python

In Azure Databricks, logging is crucial for monitoring, debugging, and auditing your notebooks, jobs, and applications. Since Databricks runs on a distributed architecture and utilizes standard Python, you can use familiar Python logging tools, along with features specific to the Databricks environment like Spark logging and MLflow tracking.

Python’s logging module provides a versatile logging system for messages of different severity levels and controls their presentation. To get started with the logging module, you need to import it to your program first, as shown below:

import logging

logging.debug("A debug message")
logging.info("An info message")
logging.warning("A warning message")
logging.error("An error message")
logging.critical("A critical message")

log levels in Python

Log levels define the severity of the event that is being logged. For example a message logged at the INFO level indicates a normal and expected event, while one that is logged at the ERROR level signifies that some unexpected error has occurred.

Each log level in Python is associated with a number (from 10 to 50) and has a corresponding module-level method in the logging module as demonstrated in the previous example. The available log levels in the logging module are listed below in increasing order of severity:

Logging Level Quick Reference

LevelMeaningWhen to Use
DEBUG (10)detailed debugging infodevelopment
INFO (20)normal messagesjob progress
WARNING (30)minor issuenon-critical issues
ERROR (40)failurerecoverable errors
CRITICAL (50)system failurestop the job

It’s important to always use the most appropriate log level so that you can quickly find the information you need. For instance, logging a message at the WARNING level will help you find potential problems that need to be investigated, while logging at the ERROR or CRITICAL level helps you discover problems that need to be rectified immediately.

By default, the logging module will only produce records for events that have been logged at a severity level of WARNING and above.

Logging basic configuration

Ensure to place the call to logging.basicConfig() before any methods such as info(), warning(), and others are used. It should also be called once as it is a one-off configuration facility. If called multiple times, only the first one will have an effect.

logging.basicConfig() example

import logging
from datetime import datetime

## set date time format
run_id = datetime.now().strftime("%Y%m%d_%H%M%S")

## Output WITH writing to a file (Databricks log file)
log_file = f"/dbfs/tmp/my_pipeline/logs/run_{run_id}.log"

## start configuing
logging.basicConfig(
    filename=log_file,
    level=logging.INFO,
    format="%(asctime)s — %(levelname)s — %(message)s",
)

## creates (or retrieves) a named logger that you will use to write log messages.
logger = logging.getLogger("pipeline")
## The string "pipeline" is just a name for the logger. It can be  anything:
## "etl"
## "my_app"
## "sales_job"
## "abc123"

simple logging example

import logging
from datetime import datetime

run_id = datetime.now().strftime("%Y%m%d_%H%M%S")
log_file = f"/dbfs/tmp/my_pipeline/logs/run_{run_id}.log"

logging.basicConfig(
    filename=log_file,
    level=logging.INFO,
    format="%(asctime)s — %(levelname)s — %(message)s",
)
logger = logging.getLogger("pipeline")

logger.info("=== Pipeline Started ===")

try:
    logger.info("Step 1: Read data")
    df = spark.read.csv(...)
    
    logger.info("Step 2: Transform")
    df2 = df.filter(...)
    
    logger.info("Step 3: Write output")
    df2.write.format("delta").save(...)

    logger.info("=== Pipeline Completed Successfully ===")

except Exception as e:
    logger.error(f"Pipeline Failed: {e}")
    raise

the log output looks this:

2025-11-21 15:05:01,112 – INFO – === Pipeline Started ===
2025-11-21 15:05:01,213 – INFO – Step 1: Read data
2025-11-21 15:05:01,315 – INFO – Step 2: Transform
2025-11-21 15:05:01,417 – INFO – Step 3: Write output
2025-11-21 15:05:01,519 – INFO – === Pipeline Completed Successfully ===

Log Rotation (Daily Files)

Log Rotation means: Your log file does NOT grow forever. Instead, it automatically creates a new log file each day (or each hour, week, etc.), and keeps only a certain number of old files.

This prevents:

  • huge log files
  • storage overflow
  • long-term disk growth
  • difficult debugging
  • slow I/O

It is very common in production systems (Databricks, Linux, App Servers, Databases). Without log rotation → 1 file becomes huge, With daily rotation:

my_log.log (today)
my_log.log.2025-11-24 (yesterday)
my_log.log.2025-11-23
my_log.log.2025-11-22

Python code that does Log Rotation

import logging
from logging.handlers import TimedRotatingFileHandler

handler = TimedRotatingFileHandler(
    "/dbfs/Volumes/logs/my_log.log",
    when="midnight",   # rotate every day
    interval=1,        # 1 day
    backupCount=30     # keep last 30 days
)

formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)

logger = logging.getLogger("rotating_logger")
logger.setLevel(logging.INFO)
logger.addHandler(handler)

logger.info("Log rotation enabled")
Hourly Log Rotation
handler = TimedRotatingFileHandler(
    "/dbfs/tmp/mylogs/hourly.log",
    when="H",       # rotate every hour
    interval=1,
    backupCount=24  # keep 24 hours
)

Size-Based Log Rotation
handler = RotatingFileHandler(
    "/dbfs/tmp/mylogs/size.log",
    maxBytes=5 * 1024 * 1024,  # 5 MB
    backupCount=5              # keep 5 old files
)

Logging to Unity Catalog Volume (BEST PRACTICE)

Create a volume first (once):

CREATE VOLUME IF NOT EXISTS my_catalog.my_schema.logs;

use it in code:

from logger_setup import get_logger

logger = get_logger(
    app_name="customer_etl",
    log_path="/dbfs/Volumes/my_catalog/my_schema/logs/customer_etl"
)

logger.info("Starting ETL pipeline")

Databricks ETL Logging Template (Production-Ready)

Features

  • Writes logs to file
  • Uses daily rotation (keeps 30 days)
  • Logs INFO, ERROR, stack traces
  • Works in notebooks + Jobs
  • Fully reusable

1. Create the logger (ready for copy & paste)

“File Version”
 import logging
from logging.handlers import TimedRotatingFileHandler

def get_logger(name="etl"):
    log_path = "/dbfs/tmp/logs/pipeline.log"   # or a UC Volume

    handler = TimedRotatingFileHandler(
        log_path,
        when="midnight",
        interval=1,
        backupCount=30
    )

    formatter = logging.Formatter(
        "%(asctime)s - %(levelname)s - %(name)s - %(message)s"
    )
    handler.setFormatter(formatter)

    logger = logging.getLogger(name)
    logger.setLevel(logging.INFO)

    # Prevent duplicate handlers in notebook re-runs
    if not logger.handlers:
        logger.addHandler(handler)

    return logger

logger = get_logger("my_pipeline")
logger.info("Logger initialized")
Unity Catalog Volume version
# If the folder doesn't exist:
dbutils.fs.mkdirs("/Volumes/my_catalog/my_schema/logs")

/Volumes/my_catalog/my_schema/logs/

# Create logger pointing to the UC Volume
import logging
from logging.handlers import TimedRotatingFileHandler

def get_logger(name="etl"):
    log_path = "/Volumes/my_catalog/my_schema/logs/pipeline.log"

    handler = TimedRotatingFileHandler(
        filename=log_path,
        when="midnight",
        interval=1,
        backupCount=30           # keep last 30 days
    )

    formatter = logging.Formatter(
        "%(asctime)s - %(levelname)s - %(name)s - %(message)s"
    )
    handler.setFormatter(formatter)

    logger = logging.getLogger(name)
    logger.setLevel(logging.INFO)

    # Prevent duplicate handlers when re-running notebook cells
    if not logger.handlers:
        logger.addHandler(handler)

    return logger

logger = get_logger("my_pipeline")
logger.info("Logger initialized")

2. Use the logger inside your ETL

logger.info("=== ETL START ===")

try:
    logger.info("Step 1: Read data")
    df = spark.read.csv("/mnt/raw/data.csv")

    logger.info("Step 2: Transform")
    df2 = df.filter("value > 0")

    logger.info("Step 3: Write output")
    df2.write.format("delta").mode("overwrite").save("/mnt/curated/data")

    logger.info("=== ETL COMPLETED ===")

except Exception as e:
    logger.error(f"ETL FAILED: {e}", exc_info=True)
    raise
Resulting log file (example)

The output file looks like this:

2025-11-21 15:12:01,233 - INFO - my_pipeline - === ETL START ===
2025-11-21 15:12:01,415 - INFO - my_pipeline - Step 1: Read data
2025-11-21 15:12:01,512 - INFO - my_pipeline - Step 2: Transform
2025-11-21 15:12:01,660 - INFO - my_pipeline - Step 3: Write output
2025-11-21 15:12:01,780 - INFO - my_pipeline - === ETL COMPLETED ===

If error:

2025-11-21 15:15:44,812 - ERROR - my_pipeline - ETL FAILED: File not found
Traceback (most recent call last):
  ...

Best Practices for Logging in Python

By utilizing logs, developers can easily monitor, debug, and identify patterns that can inform product decisions, ensure that the logs generated are informative, actionable, and scalable.

  1. Avoid the root logger
    it is recommended to create a logger for each module or component in an application.
  2. Centralize your logging configuration
    Python module that will contain all the logging configuration code.
  3. Use correct log levels
  4. Write meaningful log messages
  5. % vs f-strings for string formatting in logs
  6. Logging using a structured format (JSON)
  7. Include timestamps and ensure consistent formatting
  8. Keep sensitive information out of logs
  9. Rotate your log files
  10. Centralize your logs in one place

Conclusion

To achieve the best logging practices, it is important to use appropriate log levels and message formats, and implement proper error handling and exception logging. Additionally, you should consider implementing log rotation and retention policies to ensure that your logs are properly managed and archived.

Technical Interview Questions and Answers

The Job Interview is the single most critical step in the job hunting process. It is the definitive arena where all of your abilities must integrate. The interview itself is not a skill you possess; it is the moment you deploy your Integrated Skill Set, blending:

  1. Hard Skills (Technical Mastery): Demonstrating not just knowledge of advanced topics, but the depth of your expertise and how you previously applied it to solve complex, real-world problems.
  2. Soft Skills (Communication & Presence): Clearly articulating strategy, managing complexity under pressure, and exhibiting the leadership presence expected of senior-level and expert-level candidates.
  3. Contextual Skills (Business Acumen): Framing your solutions within the company’s business goals and culture, showing that you understand the strategic impact of your work.

This Integrated Skill represents your first real opportunity to sell your strategic value to the employer.

Landing Zone

A Microsoft Landing Zone usually refers to an Azure Landing Zone (often part of the Cloud Adoption Framework (CAF)). It is a pre-built, best-practice cloud foundation that organizations use to deploy workloads in Azure in a secure, governed, and scalable way.

A Landing Zone is the “foundation environment” in the cloud:

  • networking is ready
  • security is enforced
  • identity is centralized
  • governance is in place
  • logging & monitoring are enabled

Core Components

  • Identity & Access (Entra ID)
    • Central authentication
    • RBAC roles
  • Networking
    • Hub-Spoke architecture
    • VNet design
    • Private endpoints
  • Governance
    • Policies (Azure Policy)
    • Management Groups
    • Resource tagging standards
  • Security
    • Microsoft Defender for Cloud
    • Security baselines
    • Key Vault for secrets
  • Monitoring
    • Log Analytics
    • Azure Monitor
    • Alerting system
Star schema vs Snowflake schema

Star schema has a central fact table connected directly to denormalized dimension tables. It is simple and fast for querying.
Snowflake schema has normalized dimension tables, where dimensions are split into multiple related tables.

Snowflake = more normalized, less redundancy but more joins

Star = simpler, faster queries

How do you design a dimensional model?

I design it using business requirements:

  • Align with BI/reporting needs
  • Identify facts (measures) like sales, transactions
  • Identify dimensions like customer, product, time
  • Choose grain (very important)
  • Use surrogate keys for dimensions
  • Apply star schema for analytics performance

What is Azure Data Factory?

Azure Data Factory is a cloud-based data integration service used to create data-driven workflows for orchestrating and automating data movement and transformation across different data stores and compute services.

Key capabilities

  • Data ingestion
  • Data orchestration
  • Data transformation
  • Scheduling and monitoring
What are the core components of ADF?

The main components are:

ComponentPurpose
PipelineLogical grouping of activities
ActivitySingle task in a pipeline
DatasetData structure pointing to data
Linked ServiceConnection to external resources
TriggerSchedule or event that starts a pipeline
Integration RuntimeCompute infrastructure used to run activities
What is a Pipeline?

A pipeline is a logical grouping of activities that together perform a task such as data ingestion or transformation.

What is Integration Runtime (IR)?

Integration Runtime is the compute infrastructure used by ADF to perform data integration tasks.

  • Azure IR Fully managed compute in Azure
  • Self-hosted IR Runs on on-premises machines
  • Azure SSIS IR Used to run SSIS packages

Types:

What is a Linked Service?

A linked service defines the connection information needed for ADF to connect to external resources, example:

  • Azure SQL Database
  • Data Lake
  • databricks
  • On-Prem database
What is a Dataset?

A dataset represents the structure of data within a data store.

Difference between Pipeline and Data Flow
FeaturePipelineData Flow
PurposeOrchestrationData transformation
ComputeOrchestration engineSpark cluster
UIActivity workflowVisual transformation
How do you handle incremental loading?

Solution 1: Watermark column
last_modified_date:
Max(Last_modified)
WHERE last_modified > last_run_time

Solution 2: CDC
transaction log
change tracking

Solution 3: File-based incremental
folder partition by date

How do you implement error handling?

Try-Catch pattern
Failure path
Retry policy

Activity
├ success → next step
└ failure → error handling pipeline

What are triggers in ADF?

Triggers are used to automatically start pipelines.

TriggerPurpose
Schedule triggerTime-based execution
Tumbling windowTime-based incremental
Event triggerStorage events
What is Tumbling Window Trigger?

A tumbling window trigger runs pipelines at fixed time intervals and processes data in discrete time windows.

How do you parameterize pipelines?

ADF supports parameters at:

  • Linked Service
  • plpeline
  • dataset
What are common ADF performance optimizations?

Parallel copy: pipeline success; pipeline duration; failure rate
Staging: use blob staging
Partitioning: split large tables

How do you monitor pipelines?

Monitoring options:
ADF Monitor UI
Azure Monitor
Log Analytics

Difference between Mapping Data Flow vs Pipeline

Azure Data Factory Pipeline is an orchestration layer used to coordinate activities (copy, Databricks, API calls).
Mapping Data Flow is a visual ETL engine running on Spark for transformations without coding

How do you handle retries and failure recovery?

I handle failures using:

  • Delta Lake ACID for safe writes and rollback support
  • ADF retry policies (activity-level retries)
  • Idempotent pipeline design (safe re-runs)
  • Checkpointing in streaming jobs
  • Logging + monitoring (Log Analytics / Databricks logs)
How do you orchestrate Databricks notebooks from ADF?

I use ADF Databricks Notebook activity:

  • Prefer job clusters for cost optimization
  • Pass parameters from ADF to notebook
  • Use cluster or job cluster
  • Chain multiple notebooks in pipeline
  • Use retries + monitoring in ADF
ADF retry policies (activity-level retries)

ADF supports built-in retry at the activity level:

  • You can configure retry count + interval
  • Used for transient failures (network, timeout, throttling)
  • Works per activity (Copy, Databricks, Web, etc.)
  • Combined with timeout settings for better resilience

But retries should not replace good design (idempotency is still required).

ADF → Databricks Notebook failure: how do you know what happened?

From ADF side, I rely on:

  • Activity output logs
    • ADF captures Databricks job run URL + run ID
  • Error message propagation
    • ADF shows Databricks notebook failure message (exit code / exception summary)
  • Databricks Job Run API / UI
    • Use run ID to open detailed error logs in Databricks
  • Log Analytics integration
    • Centralized monitoring if enabled
  • Notebook logging best practice
    • Explicit try/except + logging errors back to ADF (custom messages)

So ADF gives high-level error, Databricks gives detailed stack trace.

How do you manage “Schema Drift” when ingesting data from diverse, changing corporate sources using Azure Data Factory (ADF)?

Answer: * I design a resilient ingest architecture rather than forcing hardcoded mappings. In ADF, I use Mapping Data Flows with the “Allow Schema Drift” option enabled so the pipeline doesn’t break when a source team adds a column.

When landing data into the Databricks Bronze layer, I utilize Databricks Auto Loader (cloudFiles) with Schema Evolution enabled (.option("mergeSchema", "true")). This allows Delta Lake to automatically infer and append new columns to the table schema on-the-fly, while isolating structural alerts into a monitoring log.

Describe the data storage options available in Databricks.

Databricks offers several ways to store data. First, there’s the Databricks File System for storing and managing files. Then, there’s Delta Lake, an open-source storage layer that adds ACID transactions to Apache Spark, making it more reliable. Databricks also integrates with cloud storage services like AWS S3, Azure Blob Storage, and Google Cloud Storage. Plus, you can connect to a range of external databases, both relational and NoSQL, using JDBC.

What is Databricks Delta (Delta Lakehouse) and how does it enhance the capabilities of Azure Databricks?

Databricks Delta, now known as Delta Lake, is an open-source storage layer that brings ACID transactions to Apache Spark and big data workloads. It enhances Azure Databricks by providing features like:

  • ACID transactions for data reliability and consistency.
  • Scalable metadata handling for large tables.
  • Time travel for data versioning and historical data analysis.
  • Schema enforcement and evolution.
  • Improved performance with data skipping and Z-ordering
Are there any alternative solution that is similar to Delta lakehouse?

there are several alternative technologies that provide Delta Lake–style Lakehouse capabilities (ACID + schema enforcement + time travel + scalable storage + SQL engine). such as,

  • Apache Iceberg
  • Apache Hudi
  • Snowflake (Iceberg Tables / Unistore)
  • BigQuery + BigLake
  • AWS Redshift + Lake Formation + Apache Iceberg
  • Microsoft Fabric (OneLake + Delta/DQ/DLTS)
What is Delta Live Table? Have you used DLT?

Yes. Delta Live Tables, or DLT, is a Databricks framework for building and managing reliable data pipelines. In current Databricks terminology, it is part of Lakeflow Declarative Pipelines, but DLT is still commonly used in projects and interviews.

I have used DLT in my previous projects, mainly for production data pipelines using the Bronze, Silver, and Gold architecture.

For example, in the Bronze layer, we ingested raw data from sources such as APIs, files, and enterprise systems. In Silver, we used DLT for data cleansing, validation, deduplication, CDC processing, and business transformations. The Gold layer provided curated datasets for reporting and downstream applications.

One of the key features I used was data quality expectations. I could define rules such as required business keys, valid values, and data completeness. Depending on the requirement, invalid records could be quarantined or handled separately instead of simply being dropped, while the pipeline continued processing valid data.

DLT is also declarative, which means I define what the target datasets should look like and how they depend on upstream data, rather than manually managing every execution step. Databricks manages things such as pipeline dependencies, incremental processing, monitoring, and lineage.

I also used DLT with incremental processing and CDC patterns, including identifying new or changed records using business keys and timestamps and applying changes to Delta tables.

So, in my experience, DLT is not just a transformation tool. I used it as part of a production-grade data engineering solution, covering ingestion, transformation, data quality, incremental processing, CDC, dependency management, monitoring, and the overall Bronze-Silver-Gold architecture.

Why DLT instead of regular Databricks jobs?

I would use DLT when I need a more managed and reliable data pipeline, especially for multi-stage production pipelines.

The main advantage is that DLT provides a declarative approach. I define the data transformations and dependencies, and Databricks manages much of the pipeline execution.

It also provides built-in capabilities for data quality expectations, dependency management, incremental processing, lineage, monitoring, and pipeline recovery.

For example, if I have a Bronze-to-Silver-to-Gold pipeline with multiple dependent datasets, DLT can manage those dependencies and process the data incrementally instead of requiring me to build all of that orchestration logic myself.

Regular Databricks Jobs are still very useful, especially for custom Python or PySpark processing, batch jobs, orchestration, and tasks that don’t naturally fit a declarative pipeline.

So I would say the key difference is: Databricks Jobs are primarily an execution and orchestration mechanism, while DLT provides a more complete framework for building and operating reliable data pipelines.

Delat Live table vs Telta Table side by side

Delta Table vs Delta Live Tables (Side-by-Side)

FeatureDelta TableDelta Live Tables (DLT)
DefinitionStorage layer built on Delta Lake formatManaged ETL framework built on top of Delta Lake
Main PurposeStore reliable data with ACID propertiesBuild and manage data pipelines automatically
TypeData storage / table formatData pipeline orchestration framework
ResponsibilityUser manages ETL logic manuallySystem manages ETL pipeline automatically
Pipeline ManagementNot includedBuilt-in (dependency handling, orchestration)
Data ProcessingManual (SQL / PySpark / Spark jobs)Declarative (define tables, system executes pipeline)
ETL ControlFully controlled by developerPartially automated (framework-managed execution)
Data Quality RulesNot built-inBuilt-in (expect, expect_or_drop, etc.)
MonitoringExternal tools requiredBuilt-in monitoring & observability
Lineage TrackingManual or external toolsAutomatic lineage tracking
Streaming SupportManual setup requiredNative streaming support built-in
Incremental ProcessingManually implementedAutomatically handled
Error Handling / RetryDeveloper must implementBuilt-in retry & recovery
CI/CD IntegrationPossible but manualFully integrated with pipelines
Underlying StorageParquet-based Delta formatUses Delta Tables underneath
Use CaseStore data, build tables, SQL analyticsBuild production ETL pipelines (Bronze/Silver/Gold)
Complexity LevelLower concept complexityHigher abstraction, easier operations
What is schema evolution in Delta Lake?

Schema evolution allows Delta tables to automatically or manually adapt when new columns are added or schema changes occur, without breaking pipelines.

What is Schema Enforcement?

Schema Enforcement means the system validates incoming data against a predefined schema before writing the data. It checks column names, data types, and structure to ensure data consistency and quality. And the system will reject the write or throw an error if incoming data does not match the expected schema.

What is Schema Contract?

A schema contract is an agreement between a data producer and a data consumer that defines the expected structure and rules of the data.

For example, it can define the required columns, data types, nullable rules, and sometimes business constraints.

The purpose is to make sure the producer and consumer have a clear and stable understanding of what the data should look like.

For example, if the contract says customer_id must be a non-null STRING, the producer should always provide the data in that format. If the producer wants to make a breaking change, such as changing the data type, that change needs to be agreed upon and managed.

So, in simple terms, a schema contract is the agreed data interface between the producer and the consumer.

What is Time Travel?

Time Travel is a feature that allows you to access and query previous versions of data in a table.

In Delta Lake, every data change (insert, update, delete) is versioned. This means the system keeps a history of changes, and you can query the table as it existed at a specific point in time or version.

SELECT * FROM table VERSION AS OF 5;
SELECT * FROM table TIMESTAMP AS OF '2024-01-01';
Explain how you can use Databricks to implement a Medallion Architecture (Bronze, Silver, Gold).
  1. Bronze Layer (Raw Data): Ingest raw data from various sources into the Bronze layer. This data is stored as-is, without any transformation.
  2. Silver Layer (Cleaned Data, as known Enriched layer): Clean and enrich the data from the Bronze layer. Apply transformations, data cleansing, and filtering to create more refined datasets.
  3. Gold Layer (Aggregated Data, as known Curated layer): Aggregate and further transform the data from the Silver layer to create high-level business tables or machine learning features. This layer is used for analytics and reporting.
What Is Z-Order (Databricks / Delta Lake)?

Z-Ordering in Databricks (specifically for Delta Lake tables) is an optimization technique designed to co-locate related information into the same set of data files on disk.

OPTIMIZE mytable
ZORDER BY (col1, col2);
What Is Liquid Clustering (Databricks)?

Liquid Clustering is Databricks’ next-generation data layout optimization for Delta Lake.
It replaces (and is far superior to) Z-Order.

## At creation time:
CREATE TABLE sales
CLUSTER BY (customer_id, event_date)
AS SELECT * FROM source;

## For existing tables:
ALTER TABLE sales
CLUSTER BY (customer_id, event_date);

## Trigger the actual clustering:
OPTIMIZE sales;

## Remove clustering:
ALTER TABLE sales
CLUSTER BY NONE;
What is a Dataframe, RDD, Dataset in Azure Databricks?

Dataframe refers to a specified form of tables employed to store the data within Databricks during runtime. In this data structure, the data will be arranged into two-dimensional rows and columns to achieve better accessibility.

RDD, Resilient Distributed Dataset, is a fault-tolerant, immutable collection of elements partitioned across the nodes of a cluster. RDDs are the basic building blocks that power all of Spark’s computations.

Dataset is an extension of the DataFrame API that provides compile-time type safety and object-oriented programming benefits.

What is catching and its types?

A cache is a temporary storage that holds frequently accessed data, aiming to reduce latency and enhance speed. Caching involves the process of storing data in cache memory.

What is Spark Cache / Persist (Memory Cache)

This is the standard Apache Spark feature. It stores data in the JVM Heap (Memory).

What is Databricks Disk Cache (Local Disk)

This is a Databricks-specific optimization. It automatically stores copies of remote files (Parquet/Delta) on the local NVMe SSDs of the worker nodes.

comparing .cache() and .persist()

both .cache() and .persist() are used to save intermediate results to avoid re-computing the entire lineage. The fundamental difference is that .cache() is a specific, pre-configured version of .persist().

.cache(): This is a shorthand for .persist(StorageLevel.MEMORY_ONLY). It tries to store your data in the JVM heap as deserialized objects.

.persist(): This is the more flexible version. It allows you to pass a StorageLevel to decide exactly how and where the data should be stored (RAM, Disk, or both).

How do you optimize Databricks?

When optimizing Databricks workloads, I focus on several layers. First, I optimize data layout using partitioning and Z-ordering on Delta tables. Second, I improve Spark performance by using broadcast joins, filtering data early, and caching intermediate results. Third, I tune cluster resources such as autoscaling and Photon engine. Finally, I run Delta maintenance commands like OPTIMIZE and VACUUM to manage small files and improve query performance.

Data Layout Optimization:
Partitioning:
CREATE TABLE sales
USING DELTA
PARTITIONED BY (date)

Z-Ordering:
OPTIMIZE sales
ZORDER BY (customer_id);

Liquid Clustering:

What is Photon Engine?

Photon is a high-performance query engine built in C++ that accelerates SQL queries and data processing workloads in Azure Databricks. It improves performance by using vectorized processing and optimized execution for modern hardware.

What is Data skew,

Data skew happens when some partitions have much more data than others, causing slow tasks and performance bottlenecks.

Data skew usually happens during:

  • Joins
  • GroupBy
  • Aggregations
When designing a production pipeline in Databricks, how do you diagnose and mitigate data skew or memory-related issues like Out of Memory (OOM) errors?

Answer: * Diagnosis: I look at the Spark UI. If one task takes significantly longer than others (Stage Skew) or if an executor’s memory usage spikes and drops unexpectedly, it indicates data skew. If an executor JVM dies entirely, it’s an OOM error.

I optimize partitioning using Adaptive Query Execution (AQE) or implement Liquid Clustering in Delta Lake to maintain balanced, performance-aware file sizes.

Mitigation for Skew: * If joining on a skewed key, I leverage Broadcast Joins if one table is small enough.

For larger tables, I use Skew Hints in Spark SQL (/*+ SKEW('tablename', 'columnname') */) to force Spark to salt the skewed key automatically.

Mitigation for OOM: * I review the code for anti-patterns like calling .collect() on large DataFrames.

How to fix Data Skew
  1. Salting: split one hot key into multiple keys
    for example: Add a random key to spread data across partitions.
    sample data:
    Partition 1: US (1M rows) ← Skew, slow
    Partition 2: UK (10k rows)
    Partition 3: CA (5k rows)

    doing this “Salting”
    df = df.withColumn("salt", rand() % 10)
    result:
    US_0 → 200k
    US_1 → 200k
    US_2 → 200k
    US_3 → 200k
    US_4 → 200k


    then re-partition by the new “salt” column
    df.repartition("salt")

    AFTER (Salting)
    Partition 1: US_0
    Partition 2: US_1
    Partition 3: US_2
    Partition 4: US_3
    Partition 5: US_4
  2. Better Partitioning: Repartition data using a better key.
    df.repartition(“country”)
  3. AQE:
    AQE (Adaptive Query Execution) in Spark dynamically optimizes query execution during runtime.

    How to enable AQE. It can adjust join strategies, merge small partitions, and handle data skew by splitting large partitions based on real execution statistics instead of static estimates.
    spark.conf.set("spark.sql.adaptive.enabled", "true")
How do you handle late-arriving data?

I handle late data using:

  • Reprocessing logic for backfill if needed
  • Event-time processing (not processing-time)
  • Watermarking in Structured Streaming
  • Window-based aggregations
  • Delta Lake MERGE INTO for upserts
Difference between batch vs streaming in Databricks

Batch processing processes data in chunks at scheduled intervals, while streaming processes data continuously in near real-time.

Databricks uses Structured Streaming, which treats streaming as incremental batch processing with fault tolerance.

How do you manage cluster sizing and cost optimization?

I manage cost by:

  • Using Photon and Delta optimizations to reduce compute time
  • Using autoscaling clusters
  • Choosing right node types (memory vs compute optimized)
  • Using job clusters instead of all-purpose clusters
  • Auto-termination for idle clusters
How do you validate data quality?

I validate data quality using:

  • Row count validation
  • Null checks
  • Duplicate checks
  • Data type validation
  • Referential integrity checks
  • Business rule validation

I usually automate these checks in pipelines and log failures.

How do you monitor pipeline failures?

I monitor failures using:

  • ADF Monitor
  • Databricks job monitoring
  • Log Analytics / Azure Monitor
  • Alerts and notifications (email/Teams)
  • Custom logging tables

I also track pipeline run IDs for troubleshooting.

What metrics do you track in production pipelines?

Key production metrics:

  • Pipeline success/failure rate
  • Execution duration
  • Throughput
  • Data latency
  • Row counts
  • Error counts
  • Cluster utilization/cost
  • SLA compliance

These help identify performance or reliability issues.

How do you handle schema drift?

Schema drift happens when source schema changes unexpectedly.

I handle it by:

  • Enabling schema evolution
  • Using dynamic column mapping
  • Metadata-driven pipelines
  • Auto Loader schema inference
  • Logging and alerting schema changes
  • Separating mandatory vs optional columns
How would you secure and manage secrets in Azure Databricks when connecting to external data sources?
  1. Use Azure Key Vault to store and manage secrets securely.
  2. Integrate Azure Key Vault with Azure Databricks using Databricks-backed or Azure-backed scopes.
  3. Access secrets in notebooks and jobs using the dbutils.secrets API.
    dbutils.secrets.get(scope=”<scope-name>”, key=”<key-name>”)
  4. Ensure that secret access policies are strictly controlled and audited.
How do you design a scalable ingestion pipeline?

I design it using a layered approach (Medallion Architecture):

  • Bronze: raw ingestion (batch/streaming via ADF / Auto Loader)
  • Silver: cleaned and standardized data
  • Gold: business-ready aggregated data

For scalability:

  • Use Auto Loader for incremental file ingestion
  • Use partitioning + incremental loads
  • Decouple ingestion and transformation
  • Use Delta Lake for reliability and ACID
Scenario: You need to implement a data governance strategy in Azure Databricks. What steps would you take?

  • Data Classification: Classify data based on sensitivity and compliance requirements.
  • Access Controls: Implement role-based access control (RBAC) using Azure Active Directory.
  • Data Lineage: Use tools like Databricks Lineage to track data transformations and movement.
  • Audit Logs: Enable and monitor audit logs to track access and changes to data.
  • Compliance Policies: Implement Azure Policies and Azure Purview for data governance and compliance monitoring.
Scenario: You need to optimize a Spark job that has a large number of shuffle operations causing performance issues. What techniques would you use?
  1. Repartitioning: Repartition the data to balance the workload across nodes and reduce skew.
  2. Broadcast Joins: Use broadcast joins for small datasets to avoid shuffle operations.
  3. Caching: Cache intermediate results to reduce the need for recomputation.
  4. Shuffle Partitions: Increase the number of shuffle partitions to distribute the workload more evenly.
  5. Skew Handling: Identify and handle skewed data by adding salt keys or custom partitioning strategies.
Scenario: You need to migrate an on-premises Hadoop workload to Azure Databricks. Describe your migration strategy.
  • Assessment: Evaluate the existing Hadoop workloads and identify components to be migrated.
  • Data Transfer: Use Azure Data Factory or Azure Databricks to transfer data from on-premises HDFS to ADLS.
  • Code Migration: Convert Hadoop jobs (e.g., MapReduce, Hive) to Spark jobs and test them in Databricks.
  • Optimization: Optimize the Spark jobs for performance and cost-efficiency.
  • Validation: Validate the migrated workloads to ensure they produce the same results as on-premises.
  • Deployment: Deploy the migrated workloads to production and monitor their performance.
Can you explain the difference between running a PySpark workload using a Databricks Notebook versus deploying it as modular Python code via Databricks Jobs? When would you choose one over the other?

Answer: * Databricks Notebooks are excellent for ad-hoc exploration, rapid prototyping, and interactive data analysis. They combine markdown documentation with executable code blocks, making them highly visual.

Decision Criteria: For production ETL pipelines, I advocate for modular code deployed via Databricks Jobs. It allows us to implement proper software engineering practices, such as unit testing (via pytest), static code analysis, and robust CI/CD branch policies. Notebooks are kept strictly for initial R&D or orchestrating lightweight, high-level control flows.

Modular Python Code (e.g., packaged .py files/wheels) breaks logic down into reusable, unit-testable classes and functions.

What is the difference between df.collect() and df.take(n) or df.show()

Answer: * df.collect() pulls every single row from the distributed executors across the network and dumps it into the memory of the single Driver node, converting the Spark DataFrame into a local Python list. It is highly dangerous because if the data volume exceeds the Driver’s available RAM, it triggers an immediate OOM crash.

df.take(n) and df.show(n) only retrieve the first n rows. They are safe because they cap the memory allocation on the Driver, making them ideal for debugging or lightweight data sampling.

Migrate from Hive Metastore to Unity Catalog, what would be your step-by-step strategy to handle data migration, permissions, and governance?

Step 1 — Enable Unity Catalog
Step 2 — Create Catalog and Schema
Step 3 — Configure External Location

Step 4 — Assess Hive Tables: Check:

  • managed vs external tables
  • Delta vs non-Delta
  • table size
  • dependencies
  • downstream jobs
  • permissions

Step 5 — Convert Non-Delta Tables (IMPORTANT)
CONVERT TO DELTA parquet.`abfss://container/path`;
or
CONVERT TO DELTA hive_metastore.sales.orders;

Step 6 — Migrate Tables

CREATE TABLE finance.sales.orders
DEEP CLONE hive_metastore.sales.orders;

or 

CREATE TABLE finance.sales.orders AS
SELECT * FROM hive_metastore.sales.orders;

or 
SYNC TABLE finance.sales.orders
FROM hive_metastore.sales.orders;
SYNC works mainly for: external tables and metadata sync scenarios

Step 7 — Migrate Permissions
GRANT SELECT ON TABLE finance.sales.orders TO analysts;

How do you handle credential rotation and secure workspace access using Databricks Secrets and Azure Key Vault in a heavily locked-down or regulated financial services environment?

Answer: * Hardcoding passwords or keys in code is strictly prohibited. I create an Azure Key Vault-backed Secret Scope within Databricks.

All database passwords, API keys, and service principal secrets live inside Azure Key Vault. When Databricks runs a pipeline, it fetches these secrets securely at runtime using dbutils.secrets.get(). Credential rotation is handled upstream entirely within Azure Key Vault (often via automated Azure Functions), and Databricks automatically reflects the rotated values without requiring code changes.

What is Delta Sharing?have you used it?

Yes. Delta Sharing is an open protocol developed by Databricks for securely sharing data across different organizations, platforms, and cloud environments without requiring the recipient to copy or physically move the underlying data.

I have used Delta Sharing in Databricks environments to share Delta tables and curated datasets with downstream consumers. For example, instead of creating another physical copy of the data for a consumer, we can provide controlled access to the shared data through a Delta Share.

A key advantage is that the provider can control what data is shared and who can access it. We can share specific tables or views rather than giving consumers direct access to the underlying storage.

In a typical implementation, the provider creates a share and adds the required tables or views. The recipient is then granted access and can consume the shared data using supported clients, without needing access to the provider’s underlying ADLS or cloud storage.

I also see Delta Sharing as useful for cross-organization and cross-cloud data sharing, because the consumer doesn’t necessarily need to be on the same Databricks workspace or even the same cloud platform.

So the key point is: Delta Sharing provides governed data sharing without requiring traditional data copying or giving the consumer direct access to the underlying storage.

What is Unity Catalog Volumes?

Unity Catalog Volumes provide a governed way to manage non-tabular files in cloud storage through Unity Catalog.

in short, Delta tables are for structured/tabular data; Volumes are for files, unstructured.

Unity Catalog Volumes provide a governed way to access and manage files in cloud storage that are not necessarily Delta tables.

I have used Volumes in Databricks environments for file-based data such as documents, JSON, CSV, and other files that need to be accessed by data engineering or AI workloads.

There are two main types: managed volumes and external volumes. With a managed volume, Databricks manages the underlying storage. With an external volume, the data remains in an external cloud storage location such as ADLS Gen2, while Unity Catalog provides centralized governance and access control.

One of the main benefits is that users and workloads can access files through a governed Unity Catalog path such as /Volumes/<catalog>/<schema>/<volume>/..., rather than directly accessing cloud storage credentials or storage paths.

This is particularly useful when we need to apply centralized access control, auditing, and governance to file-based data.

So, in simple terms, Unity Catalog tables are primarily for governed structured data, while Volumes provide governed access to files.

What are Synapse SQL Workspaces and how are they used?

Synapse SQL Workspaces are the environments within Azure Synapse Analytics where users can perform data querying and management tasks. They include:

  • Provisioned SQL Pools: Used for large-scale, high-performance data warehousing. Users can create and manage databases, tables, and indexes, and run complex queries.
  • On-Demand SQL Pools: Allow users to query data directly from Azure Data Lake without creating a dedicated data warehouse. It is ideal for interactive and exploratory queries.
 What is the difference between On-Demand SQL Pool and Provisioned SQL Pool?

The primary difference between On-Demand SQL Pool and Provisioned SQL Pool lies in their usage and scalability:

  • On-Demand SQL Pool: Allows users to query data stored in Azure Data Lake without requiring a dedicated resource allocation. It is best for ad-hoc queries and does not incur costs when not in use. It scales automatically based on query demand.
  • Provisioned SQL Pool: Provides a dedicated set of resources for running data warehousing workloads. It is optimized for performance and can handle large-scale data operations. Costs are incurred based on the provisioned resources and are suitable for predictable, high-throughput workloads.
 How does Azure Synapse Analytics handle data integration?

Azure Synapse Analytics handles data integration through Synapse Pipelines, which is a data integration service built on Azure Data Factory. It enables users to:

  • Ingest Data: Extract data from various sources, including relational databases, non-relational data stores, and cloud-based services.
  • Transform Data: Use data flows and data wrangling to clean and transform data.
  • Orchestrate Workflows: Schedule and manage data workflows, including ETL (Extract, Transform, Load) processes.
  • Data Integration Runtime: Utilizes Azure Integration Runtime for data movement and transformation tasks.

Can you explain the concept of “Dedicated SQL Pool” in Azure Synapse Analytics?

Dedicated SQL Pool is a provisioned, high-performance relational database.

  • Data Storage: Data must be ingested and stored internally in a proprietary columnar format. It follows a Schema-on-Write approach.
  • Architecture: Uses MPP (Massively Parallel Processing) architecture. Data is sharded into 60 distributions and processed by multiple compute nodes in parallel.
  • Cost: Billed by the hour based on the provisioned DWUs. You can pause it when not in use to save costs.
  • Best For: Stable production reporting, TB/PB scale enterprise data warehousing, and high-concurrency queries needing sub-second response.
What is Serverless SQL Pool and when would you use it?

Serverless SQL Pool is an on-demand, compute-only query engine with no internal storage.

  • Data Location: It does not store data. Data remains in the Data Lake (ADLS Gen2) in open formats like Parquet, CSV, or JSON.
  • Mechanism: Uses the OPENROWSET function to query lake files directly. It follows a Schema-on-Read approach.
  • Cost: Billed per query based on data scanned (approx. $5 USD per TB). Cost is $0 if no queries are run.
  • Best For: Rapid data discovery, building a Logical Data Warehouse, and ad-hoc data validation.

It is a managed Apache Spark 3 instance easily created and configured within Azure.

  • Managed Cluster: You don’t manage servers; you just select the node size and the number of nodes.
  • Auto-Scale & Auto-Pause: It automatically scales nodes based on workload and pauses after 5 minutes of inactivity to save costs.
  • Language Support: Supports PySpark (Python), Spark SQL, Scala, and .NET.

Can you give an example of a prompt design you used to help document a complex pipeline or generate validation test cases, including the constraints you applied?

Answer: * Effective prompt design relies on clear persona, context, and explicit constraints.

Example Prompt: “You are an expert Data Architect. Act as a technical documentation writer. Analyze the following PySpark code which performs a Type 2 Slowly Changing Dimension (SCD Type 2) merge. Write a technical markdown document explaining the data lineage, column mappings, and transformation logic. Constraints: Do not use placeholder code. Do not explain standard PySpark syntax. Format the column mappings strictly in a markdown table. Highlight the idempotency mechanics of the code.”

Using Generative AI tools responsibly to improve engineering velocity. How do you use tools like GitHub Copilot or ChatGPT to scaffold notebooks, write unit tests, or optimize slow SQL queries?

I use generative AI tools like GitHub Copilot and ChatGPT as productivity accelerators across development, testing, and optimization, but always within a controlled and validated engineering workflow.

For example, when building Databricks notebooks, I use Copilot to scaffold initial PySpark structures such as data ingestion patterns, Delta table reads/writes, and common transformation templates. This helps me quickly set up a working baseline, especially for standard ETL/ELT pipelines, while I focus on business logic, data modeling, and performance design.

For unit testing, I use ChatGPT or Copilot to generate initial PySpark or SQL test cases, such as null checks, schema validation, row count verification, and data quality rules. I then refine these tests to align with data contracts and production expectations, ensuring they are meaningful and not just syntactically correct.

For SQL optimization, I often use ChatGPT to analyze slow queries and suggest improvements like better join strategies, partition pruning, or indexing considerations. However, I always validate improvements using query execution plans, Databricks Spark UI, and actual runtime benchmarks before applying changes.

In all cases, I treat AI as an assistant rather than an authority. I ensure no sensitive or PII data is included in prompts, and all AI-generated code is reviewed, tested, and validated before production deployment. The goal is to improve engineering velocity without compromising correctness, security, or governance.

What are your strict guardrails regarding Data Governance and Security when using Generative AI tools? How do you ensure that sensitive corporate data, business logic, or PII (Personally Identifiable Information) are never leaked in a prompt?

Answer: * Data privacy is paramount, especially in financial services. My absolute rule is that no actual client data, proprietary database schemas, or PII can ever enter a commercial AI prompt.

When utilizing AI for troubleshooting or code generation, I completely anonymize and abstract the prompt. I swap out proprietary table names for generic placeholders (e.g., Table_A, Table_B), obfuscate custom column names (e.g., changing account_balance_cad to metric_1), and generate synthetic mockup rows if I need to illustrate a data structure issue.

AI can occasionally “hallucinate” code or logic. What is your process for validating AI-assisted code outputs before submitting a Pull Request (PR) for a peer review?

I never take AI-generated code at face value; it must be fully verified. My validation process includes:

Unit Testing: Verify the output against expected boundaries (checking edge cases like handling of Null values or empty DataFrames). Only after it passes automated testing do I integrate it into the codebase and open a PR.

Code Review & Linting: Check for syntax errors, deprecated Spark methods, or non-existent library parameters.

Local/Dev Execution: Run the generated code block inside a isolated scratchpad environment using a small, controlled sample dataset.

Can you talk about database locker?

Database locking is the mechanism a database uses to control concurrent access to data so that transactions stay consistent, isolated, and safe.

Locking prevents:

  • Dirty reads
  • Lost updates
  • Write conflicts
  • Race conditions

Types of Locks:

1. Shared Lock (S)

  • Used when reading data
  • Multiple readers allowed
  • No writers allowed

2. Exclusive Lock (X)

  • Used when updating or inserting
  • No one else can read or write the locked item

3. Update Lock (U) (SQL Server specific)

  • Prevents deadlocks when upgrading from Shared → Exclusive
  • Only one Update lock allowed

4. Intention Locks (IS, IX, SIX)

Used at table or page level to signal a lower-level lock is coming.

5. Row / Page / Table Locks

Based on granularity:

  • Row-level: Most common, best concurrency
  • Page-level: Several rows together
  • Table-level: When scanning or modifying large portions

DB engines automatically escalate:

Row → Page → Table
when there are too many small locks.

Can you talk on Deadlock?

A deadlock happens when:

  • Transaction A holds Lock 1 and wants Lock 2
  • Transaction B holds Lock 2 and wants Lock 1

Both wait on each other → neither can move → database detects → kills one transaction (“deadlock victim”).

Deadlocks usually involve one writer + one writer, but can also involve readers depending on isolation level.

How to Troubleshoot Deadlocks?
A: In SQL Server: Enable Deadlock Graph Capture
run:
ALTER DATABASE [YourDB] SET DEADLOCK_PRIORITY NORMAL;

use:
DBCC TRACEON (1222, -1);
DBCC TRACEON (1204, -1);
B: Interpret the Deadlock Graph

You will see:

  • Processes (T1, T2…)
  • Resources (keys, pages, objects)
  • Types of locks (X, S, U, IX, etc.)
  • Which statement caused the deadlock

Look for:

  • Two queries touching the same index/rows in different order
  • A scanning query locking too many rows
  • Missed indexes
  • Query patterns that cause U → X lock upgrades
C. Identify
  • The exact tables/images involved
  • The order of locking
  • The hotspot row or range
  • Rows with heavy update/contention

This will tell you what to fix.

How to Prevent Deadlocks (Practical + Senior-Level)
  • Always update rows in the same order
  • Keep transactions short
  • Use appropriate indexes
  • Use the correct isolation level
  • Avoid long reads before writes

Can you discuss on database normalization and denormalization

Normalization is the process of structuring a relational database to minimize data redundancy (duplicate data) and improve data integrity.

Normal FormRule SummaryProblem Solved
1NF (First)Eliminate repeating groups; ensure all column values are atomic (indivisible).Multi-valued columns, non-unique rows.
2NF (Second)Be in 1NF, AND all non-key attributes must depend on the entire primary key.Partial Dependency (non-key attribute depends on part of a composite key).
3NF (Third)Be in 2NF, AND eliminate transitive dependency (non-key attribute depends on another non-key attribute).Redundancy due to indirect dependencies.
BCNF (Boyce-Codd)A stricter version of 3NF; every determinant (column that determines another column) must be a candidate key.Edge cases involving multiple candidate keys.

Denormalization is the process of intentionally introducing redundancy into a previously normalized database to improve read performance and simplify complex queries.

  • Adding Redundant Columns: Copying a value from one table to another (e.g., copying the CustomerName into the Orders table to avoid joining to the Customer table every time an order is viewed).
  • Creating Aggregate/Summary Tables: Storing pre-calculated totals, averages, or counts to avoid running expensive aggregate functions at query time (e.g., a table that stores the daily sales total).
  • Merging Tables: Combining two tables that are frequently joined into a single, wider table.
How do you optimize slow SQL queries?

I optimize SQL by:

  • Checking execution plan first
  • Adding proper indexes (if relational DB)
  • Reducing data scanned (filter early)
  • Avoiding unnecessary joins
  • Using partition pruning in Spark/Delta
  • Using caching or materialized views
  • Optimizing joins (broadcast small tables)

Comparison of Microsoft Fabric, Azure Synapse Analytics (ASA), Azure Data Factory (ADF), and Azure Databricks (ADB)

Today, data engineers have a wide array of tools and platforms at their disposal for data engineering projects. Popular choices include Microsoft Fabric, Azure Synapse Analytics (ASA), Azure Data Factory (ADF), and Azure Databricks (ADB). It’s common to wonder which one is the best fit for your specific needs.

Side by Side comparison

Here’s a concise comparison of Microsoft Fabric, Azure Synapse Analytics, Azure Data Factory (ADF), and Azure Databricks (ADB) based on their key features, use cases, and differences:

FeatureMicrosoft FabricAzure Synapse AnalyticsAzure Data Factory (ADF)Azure Databricks (ADB)
TypeUnified SaaS analytics platformIntegrated analytics serviceCloud ETL/ELT serviceApache Spark-based analytics platform
Primary Use CaseEnd-to-end analytics (Data Engineering, Warehousing, BI, Real-Time)Large-scale data warehousing & analyticsData integration & orchestrationBig Data processing, ML, AI, advanced analytics
Data IntegrationBuilt-in Data Factory capabilitiesSynapse Pipelines (similar to ADF)Hybrid ETL/ELT pipelinesLimited (relies on Delta Lake, ADF, or custom code)
Data WarehousingOneLake (Delta-Parquet based)Dedicated SQL pools (MPP)Not applicableCan integrate with Synapse/Delta Lake
Big Data ProcessingSpark-based (Fabric Spark)Spark pools (serverless/dedicated)No (orchestration only)Optimized Spark clusters (Delta Lake)
Real-Time AnalyticsYes (Real-Time Hub)Yes (Synapse Real-Time Analytics)NoYes (Structured Streaming)
Business IntelligencePower BI (deeply integrated)Power BI integrationNoLimited (via dashboards or Power BI)
Machine LearningBasic ML integrationML in Spark poolsNoFull ML/DL support (MLflow, AutoML)
Pricing ModelCapacity-based (Fabric SKUs)Pay-as-you-go (serverless) or dedicatedActivity-basedDBU-based (compute + storage)
Open Source SupportLimited (Delta-Parquet)Limited (Spark, SQL)NoFull (Spark, Python, R, ML frameworks)
GovernanceCentralized (OneLake, Purview)Workspace-levelLimitedWorkspace-level (Unity Catalog)

Key Differences

  • Fabric vs Synapse: Fabric is a fully managed SaaS (simpler, less configurable), while Synapse offers more control (dedicated SQL pools, Spark clusters).
  • ADF vs Synapse Pipelines: Synapse Pipelines = ADF inside Synapse (same engine).
  • ADB vs Fabric Spark: ADB has better ML & open-source support, while Fabric Spark is simpler & integrated with Power BI.

When to Use Which

  1. Microsoft Fabric
    • Best for end-to-end analytics in a unified SaaS platform (no infrastructure management).
    • Combines data engineering, warehousing, real-time, and BI in one place.
    • Good for Power BI-centric organizations.
  2. Azure Synapse Analytics
    • Best for large-scale data warehousing with SQL & Spark processing.
    • Hybrid of ETL (Synapse Pipelines), SQL Pools, and Spark analytics.
    • More flexible than Fabric (supports open formats like Parquet, CSV).
  3. Azure Data Factory (ADF)
    • Best for orchestrating ETL/ELT workflows (no compute/storage of its own).
    • Used for data movement, transformations, and scheduling.
    • Often paired with Synapse or Databricks.
  4. Azure Databricks (ADB)
    • Best for advanced analytics, AI/ML, and big data processing with Spark.
    • Optimized for Delta Lake (ACID transactions on data lakes).
    • Preferred for data science teams needing MLflow, AutoML, etc.

Which One Should You Choose?

  • For a fully integrated Microsoft-centric solution → Fabric
  • For large-scale data warehousing + analytics → Synapse
  • For ETL/data movement → ADF (or Synapse Pipelines)
  • For advanced Spark-based analytics & ML → Databricks

Data Quality Framework (DQX)

Data quality is more critical than ever in today’s data-driven world. Organizations are generating and collecting vast amounts of data, and the ability to trust and leverage this information is paramount for success. Poor data quality can have severe negative impacts, ranging from flawed decision-making to regulatory non-compliance and significant financial losses.

Key Dimensions of Data Quality (DAMA-DMBOK or ISO 8000 Standards)

A robust DQX evaluates data across multiple dimensions:

  • Accuracy: Data correctly represents real-world values.
  • Completeness: No missing or null values where expected.
  • Consistency: Data is uniform across systems and over time.
  • Timeliness: Data is up-to-date and available when needed.
  • Validity: Data conforms to defined business rules (e.g., format, range).
  • Uniqueness: No unintended duplicates.
  • Integrity: Relationships between datasets are maintained.

What is Data Quality Framework (DQX)

A Data Quality Framework (DQX) is an open-source framework from Databricks Labs designed to simplify and automate data quality checks for PySpark workloads on both batch and streaming data.

DAX is a structured approach to assessing, monitoring, and improving the quality of data within an organization. It define, validate, and enforce data quality rules across your data pipelines. It ensures that data is accurate, consistent, complete, reliable, and fit for its intended use. so it can be used confidently for analytics, reporting, compliance, and decision-making.

This article will explore how the DQX framework helps improve data reliability, reduce data errors, and enforce compliance with data quality standards. We will step by step go through all steps, from setup and use DQX framework in databricks notebook with code snippets to implement data quality checks.

DQX usage in the Lakehouse Architecture

In the Lakehouse architecture, new data validation should happen during data entry into the curated layer to ensure bad data is not propagated to the subsequent layers. With DQX, you can implement Dead-Letter pattern to quarantine invalid data and re-ingest it after curation to ensure data quality constraints are met. The data quality can be monitored in real-time between layers, and the quarantine process can be automated.

Credits: https://databrickslabs.github.io/dqx/docs/motivation/

Components of a Data Quality Framework

A DQX typically includes:

A. Data Quality Assessment

  • Profiling: Analyze data to identify anomalies (e.g., outliers, nulls).
  • Metrics & KPIs: Define measurable standards (e.g., % completeness, error rates).
  • Benchmarking: Compare against industry standards or past performance.

B. Data Quality Rules & Standards

  • Define validation rules (e.g., “Email must follow RFC 5322 format”).
  • Implement checks at the point of entry (e.g., form validation) and during processing.

C. Governance & Roles

  • Assign data stewards responsible for quality.
  • Establish accountability (e.g., who fixes issues? Who approves changes?).

D. Monitoring & Improvement

  • Automated checks: Use tools like Great Expectations, Talend, or custom scripts.
  • Root Cause Analysis (RCA): Identify why errors occur (e.g., system glitches, human input).
  • Continuous Improvement: Iterative fixes (e.g., process changes, user training).

E. Tools & Technology

  • Data Quality Tools: Informatica DQ, IBM InfoSphere, Ataccama, or open-source (Apache Griffin).
  • Metadata Management: Track data lineage and quality scores.
  • AI/ML: Anomaly detection (e.g., identifying drift in datasets).

F. Culture & Training

  • Promote data literacy across teams.
  • Encourage reporting of data issues without blame.

Using Databricks DQX Framework in a Notebook

Step by Step Implementing DQX

Step 1: Install the DQX Library

install it using the Databricks Labs CLI:

%pip install databricks-labs-dqx

# Restart the kernel after the package is installed in the notebook:
# in a separate cell run:
dbutils.library.restartPython()

Step 2: Initialize the Environment and read input data

Set up the necessary environment for running the Databricks DQX framework, including:

Importing the key components from the Databricks DQX library.
  • DQProfiler: Used for profiling the input data to understand its structure and generate summary statistics.
  • DQGenerator: Generates data quality rules based on the profiles.
  • DQEngine: Executes the defined data quality checks.
  • WorkspaceClient: Handles communication with the Databricks workspace.
Import Libraries
from databricks.labs.dqx.profiler.profiler import DQProfiler
from databricks.labs.dqx.profiler.generator import DQGenerator
from databricks.labs.dqx.engine import DQEngine
from databricks.sdk import WorkspaceClient
Loading the input data that you want to evaluate.
# Read the input data from a Delta table
input_df = spark.read.table("catalog.schema.table")
Establishing a connection to the Databricks workspace.
# Initialize the WorkspaceClient to interact with the Databricks workspace
ws = WorkspaceClient()

# Initialize a DQProfiler instance with the workspace client
profiler = DQProfiler(ws)
Profiling for data quality.
# Profile the input DataFrame to get summary statistics and data profiles

summary_stats, profiles = profiler.profile(input_df)
Generate DQX quality rules/checks
# generate DQX quality rules/checks
generator = DQGenerator(ws)
checks = generator.generate_dq_rules(profiles)  # with default level "error"

dq_engine = DQEngine(ws)
Save checks in arbitrary workspace location
# save checks in arbitrary workspace location
dq_engine.save_checks_in_workspace_file(checks, workspace_path="/Shared/App1/checks.yml")
Generate DLT expectations
# generate DLT expectations
dlt_generator = DQDltGenerator(ws)

dlt_expectations = dlt_generator.generate_dlt_rules(profiles, language="SQL")
print(dlt_expectations)

dlt_expectations = dlt_generator.generate_dlt_rules(profiles, language="Python")
print(dlt_expectations)

dlt_expectations = dlt_generator.generate_dlt_rules(profiles, language="Python_Dict")
print(dlt_expectations)

The profiler samples 30% of the data (sample ratio = 0.3) and limits the input to 1000 records by default.

Profiling a Table

Tables can be loaded and profiled using profile_table.

from databricks.labs.dqx.profiler.profiler import DQProfiler
from databricks.sdk import WorkspaceClient

# Profile a single table directly
ws = WorkspaceClient()
profiler = DQProfiler(ws)

# Profile a specific table with custom options
summary_stats, profiles = profiler.profile_table(
    table="catalog1.schema1.table1",
    columns=["col1", "col2", "col3"],  # specify columns to profile
    options={
        "sample_fraction": 0.1,  # sample 10% of data
        "limit": 500,            # limit to 500 records
        "remove_outliers": True, # enable outlier detection
        "num_sigmas": 2.5       # use 2.5 standard deviations for outliers
    }
)

print("Summary Statistics:", summary_stats)
print("Generated Profiles:", profiles)
Profiling Multiple Tables

The profiler can discover and profile multiple tables in Unity Catalog. Tables can be passed explicitly as a list or be included/excluded using regex patterns.

from databricks.labs.dqx.profiler.profiler import DQProfiler
from databricks.sdk import WorkspaceClient

ws = WorkspaceClient()
profiler = DQProfiler(ws)

# Profile several tables by name:
results = profiler.profile_tables(
    tables=["main.data.table_001", "main.data.table_002"]
)

# Process results for each table
for summary_stats, profiles in results:
    print(f"Table statistics: {summary_stats}")
    print(f"Generated profiles: {profiles}")

# Include tables matching specific patterns
results = profiler.profile_tables(
    patterns=["$main.*", "$data.*"]
)

# Process results for each table
for summary_stats, profiles in results:
    print(f"Table statistics: {summary_stats}")
    print(f"Generated profiles: {profiles}")

# Exclude tables matching specific patterns
results = profiler.profile_tables(
    patterns=["$sys.*", ".*_tmp"],
    exclude_matched=True
)

# Process results for each table
for summary_stats, profiles in results:
    print(f"Table statistics: {summary_stats}")
    print(f"Generated profiles: {profiles}")

Profiling Options

The profiler supports extensive configuration options to customize the profiling behavior.

from databricks.labs.dqx.profiler.profiler import DQProfiler
from databricks.sdk import WorkspaceClient

# Custom profiling options
custom_options = {
# Sampling options
"sample_fraction": 0.2, # Sample 20% of the data
"sample_seed": 42, # Seed for reproducible sampling
"limit": 2000, # Limit to 2000 records after sampling

# Outlier detection options
"remove_outliers": True, # Enable outlier detection for min/max rules
"outlier_columns": ["price", "age"], # Only detect outliers in specific columns
"num_sigmas": 2.5, # Use 2.5 standard deviations for outlier detection

# Null value handling
"max_null_ratio": 0.05, # Generate is_not_null rule if <5% nulls

# String handling
"trim_strings": True, # Trim whitespace from strings before analysis
"max_empty_ratio": 0.02, # Generate is_not_null_or_empty if <2% empty strings

# Distinct value analysis
"distinct_ratio": 0.01, # Generate is_in rule if <1% distinct values
"max_in_count": 20, # Maximum items in is_in rule list

# Value rounding
"round": True, # Round min/max values for cleaner rules
}

ws = WorkspaceClient()
profiler = DQProfiler(ws)

# Apply custom options to profiling
summary_stats, profiles = profiler.profile(input_df, options=custom_options)

# Apply custom options when profiling tables
tables = [
"dqx.demo.test_table_001",
"dqx.demo.test_table_002",
"dqx.demo.test_table_003", # profiled with default options
]
table_options = {
"dqx.demo.test_table_001": {"limit": 2000},
"dqx.demo.test_table_002": {"limit": 5000},
}
summary_stats, profiles = profiler.profile_tables(tables=tables, options=table_options)

Understanding output

Assuming the sample data is:

customer_idcustomer_namecustomer_emailis_activestart_dateend_date
1Alicealice@mainri.ca12025-01-24null
2Bobbob_new@mainri.ca12025-01-24null
3Charlieinvalid_email12025-01-24null
3Charlieinvalid_email02025-01-242025-01-24
# Initialize the WorkspaceClient to interact with the Databricks workspace
ws = WorkspaceClient()

# Initialize a DQProfiler instance with the workspace client
profiler = DQProfiler(ws)

# Read the input data from a Delta table
input_df = spark.read.table("catalog.schema.table")

# Display a sample of the input data
input_df.display()

# Profile the input DataFrame to get summary statistics and data profiles
summary_stats, profiles = profiler.profile(input_df)

Upon checking the summary and profile of my input data generated, below are the results generated by DQX

print(summary_stats)

Summary of input data on all the columns in input dataframe

# Summary of input data on all the columns in input dataframe
{
  "customer_id": {
    "count": 4,
    "mean": 2.25,
    "stddev": 0.9574271077563381,
    "min": 1,
    "25%": 1,
    "50%": 2,
    "75%": 3,
    "max": 3,
    "count_non_null": 4,
    "count_null": 0
  },
  "customer_name": {
    "count": 4,
    "mean": null,
    "stddev": null,
    "min": "Alice",
    "25%": null,
    "50%": null,
    "75%": null,
    "max": "Charlie",
    "count_non_null": 4,
    "count_null": 0
  },
  "customer_email": {
    "count": 4,
    "mean": null,
    "stddev": null,
    "min": "alice@example.com",
    "25%": null,
    "50%": null,
    "75%": null,
    "max": "charlie@example.com",
    "count_non_null": 4,
    "count_null": 0
  },
  "is_active": {
    "count": 4,
    "mean": 0.75,
    "stddev": 0.5,
    "min": 0,
    "25%": 0,
    "50%": 1,
    "75%": 1,
    "max": 1,
    "count_non_null": 4,
    "count_null": 0
  },
  "start_date": {
    "count": 4,
    "count_non_null": 4,
    "count_null": 0,
    "min": "2025-01-24",
    "max": "2025-01-24",
    "mean": "2025-01-24"
  },
  "end_date": {
    "count": 4,
    "count_non_null": 1,
    "count_null": 3,
    "min": 1737676800,
    "max": 1737676800
  }
}

print(profiles)
# Default Data profile generated based on input data
DQProfile(
  name='is_not_null',
  column='customer_id',
  description=None,
  parameters=None
),
DQProfile(
  name='min_max',
  column='customer_id',
  description='Real min/max values were used',
  parameters={
    'min': 1,
    'max': 3
  }
),
DQProfile(
  name='is_not_null',
  column='customer_name',
  description=None,
  parameters=None
),
DQProfile(
  name='is_not_null',
  column='customer_email',
  description=None,
  parameters=None
),
DQProfile(
  name='is_not_null',
  column='is_active',
  description=None,
  parameters=None
),
DQProfile(
  name='is_not_null',
  column='start_date',
  description=None,
  parameters=None
)

Step 3: Understanding checks applied at data

With the below snippet, we can understand the default checks applied at input data, which generated the data profile as mentioned in previous step.

# generate DQX quality rules/checks
generator = DQGenerator(ws)
checks = generator.generate_dq_rules(profiles)

print(checks)
# Checks applied on input data
[{
  'check': {
    'function': 'is_not_null',
    'arguments': {
      'col_name': 'customer_id'
    }
  },
  'name': 'customer_id_is_null',
  'criticality': 'error'
},
{
  'check': {
    'function': 'is_in_range',
    'arguments': {
      'col_name': 'customer_id',
      'min_limit': 1,
      'max_limit': 3
    }
  },
  'name': 'customer_id_isnt_in_range',
  'criticality': 'error'
},
{
  'check': {
    'function': 'is_not_null',
    'arguments': {
      'col_name': 'customer_name'
    }
  },
  'name': 'customer_name_is_null',
  'criticality': 'error'
},
{
  'check': {
    'function': 'is_not_null',
    'arguments': {
      'col_name': 'customer_email'
    }
  },
  'name': 'customer_email_is_null',
  'criticality': 'error'
},
{
  'check': {
    'function': 'is_not_null',
    'arguments': {
      'col_name': 'is_active'
    }
  },
  'name': 'is_active_is_null',
  'criticality': 'error'
},
{
  'check': {
    'function': 'is_not_null',
    'arguments': {
      'col_name': 'start_date'
    }
  },
  'name': 'start_date_is_null',
  'criticality': 'error'
}]

Step 4: Define custom Data Quality Expectations

In addition to the automatically generated checks, you can define your own custom rules to enforce business-specific data quality requirements. This is particularly useful when your organization has unique validation criteria that aren’t covered by the default checks. By using a configuration-driven approach (e.g., YAML), you can easily maintain and update these rules without modifying your pipeline code.

For example, you might want to enforce that:

  • Customer IDs must not be null or empty.
  • Email addresses must match a specific domain format (e.x: @example.com).
# Define custom data quality expectations.
import yaml

checks_custom = yaml.safe_load("""
- check:
    arguments:
        col_name: customer_id
    function: is_not_null_and_not_empty
    criticality: error
    name: customer_id_is_null
- check:
    arguments:
        col_name: customer_email
        regex: '^[A-Za-z0-9._%+-]+@example\.com$'
    function: regex_match
    criticality: error
    name: customer_emaild_is_not_valid""")
# Validate the custom data quality checks
status = DQEngine.validate_checks(checks_custom)

# The above variable for the custom config yaml file can also be pased from workspace file path as given below:
status = DQEngine.validate_checks("path to yaml file in workspace")

# Assert that there are no errors in the validation status
assert not status.has_errors

Step 5: Applying the custom rules and generating results

Once your custom data quality rules have been defined and validated, the next step is to apply them to your input data. The DQEngine facilitates this by splitting your dataset into two categories:

  • Silver Data: Records that meet all quality expectations.
  • Quarantined Data: Records that fail one or more quality checks.

This approach allows you to separate valid and invalid data for further inspection and remediation. The valid records can proceed to downstream processes, while the quarantined records can be analyzed to determine the cause of failure (e.g., missing values, incorrect formats).

Here’s how you can apply the rules and generate the results:

# Create a DQEngine instance with the WorkspaceClient
dq_engine = DQEngine(WorkspaceClient())

# Apply quality checks and split the DataFrame into silver and quarantine DataFrames
silver_df, quarantine_df = dq_engine.apply_checks_by_metadata_and_split(input_df_1, checks_custom)
Quarantined data – Not matching the rules

Summary

In essence, data quality is no longer just an IT concern; it’s a fundamental business imperative. In today’s complex and competitive landscape, the success of an organization hinges on its ability to leverage high-quality, trusted data for every strategic and operational decision.

A Data Quality Framework (DQX) helps organizations:

  • Establish clear quality standards
  • Implement automated checks
  • Track and resolve issues
  • Ensure trust in data

https://databrickslabs.github.io/dqx/docs/motivation

https://medium.com/@nivethanvenkat28/revolutionizing-data-quality-checks-using-databricks-dqx-f2a49d83c3c6