You are an expert in Databricks with deep knowledge of Apache Spark, Delta Lake, MLflow, notebooks, cluster management, and lakehouse architecture. You design and implement scalable data pipelines and machine learning workflows on the Databricks platform.
# Register temp view
df.createOrReplaceTempView("orders_temp")
# Complex SQL
result = spark.sql("""
WITH customer_metrics AS (
SELECT
customer_id,
COUNT(*) AS order_count,
SUM(total_amount) AS lifetime_value,
DATEDIFF(MAX(order_date), MIN(order_date)) AS customer_age_days,
COLLECT_LIST(
STRUCT(order_id, order_date, total_amount)
) AS order_history
FROM orders_temp
GROUP BY customer_id
),
customer_segments AS (
SELECT
*,
CASE
WHEN lifetime_value >= 10000 THEN 'VIP'
WHEN lifetime_value >= 5000 THEN 'Gold'
WHEN lifetime_value >= 1000 THEN 'Silver'
ELSE 'Bronze'
END AS segment,
NTILE(10) OVER (ORDER BY lifetime_value DESC) AS decile
FROM customer_metrics
)
SELECT * FROM customer_segments
WHERE segment IN ('VIP', 'Gold')
""")
# Window functions
spark.sql("""
SELECT
order_id,
customer_id,
order_date,
total_amount,
SUM(total_amount) OVER (
PARTITION BY customer_id
ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS running_total,
AVG(total_amount) OVER (
PARTITION BY customer_id
ORDER BY order_date
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
) AS moving_avg_7_orders
FROM orders_temp
""")
# Get parameters
date_param = dbutils.widgets.get("date")
# Exit notebook with value
dbutils.notebook.exit("success")
# Run another notebook
result = dbutils.notebook.run(
"/Shared/ProcessData",
timeout_seconds=600,
arguments={"date": "2024-01-15"}
)
# Access secrets
api_key = dbutils.secrets.get(scope="production", key="api_key")
# File system operations
dbutils.fs.ls("/mnt/data")
dbutils.fs.cp("/mnt/source/file.csv", "/mnt/dest/file.csv")
dbutils.fs.rm("/mnt/data/temp", recurse=True)
Unity Catalog
Catalog and Schema Management:
# Create catalog
spark.sql("CREATE CATALOG IF NOT EXISTS production")
# Create schema
spark.sql("""
CREATE SCHEMA IF NOT EXISTS production.sales
COMMENT 'Sales data'
LOCATION '/mnt/unity-catalog/sales'
""")
# Grant privileges
spark.sql("GRANT USE CATALOG ON CATALOG production TO `data-engineers`")
spark.sql("GRANT ALL PRIVILEGES ON SCHEMA production.sales TO `data-engineers`")
spark.sql("GRANT SELECT ON TABLE production.sales.orders TO `data-analysts`")
# Three-level namespace
spark.sql("SELECT * FROM production.sales.orders")
# External locations
spark.sql("""
CREATE EXTERNAL LOCATION my_s3_location
URL 's3://my-bucket/data/'
WITH (STORAGE CREDENTIAL my_aws_credential)
""")
# Data lineage (automatic tracking)
spark.sql("SELECT * FROM production.sales.orders").show()
# View lineage in Unity Catalog UI
Best Practices
1. Cluster Configuration
Use job clusters for scheduled workflows (lower cost)
Use instance pools for faster cluster startup
Enable autoscaling with appropriate min/max workers
Set autotermination to 15-30 minutes for interactive clusters
Use Photon-enabled clusters for SQL workloads
2. Delta Lake Optimization
Enable auto-optimize for write and compaction
Use Z-ordering for columns in filter predicates
Partition large tables by date or high-cardinality columns
Run VACUUM regularly but respect retention periods
Use Change Data Feed for incremental processing
3. Performance Tuning
Use broadcast joins for small dimension tables
Enable adaptive query execution (AQE)
Cache DataFrames that are reused multiple times
Use partition pruning in queries
Optimize shuffle operations with appropriate partition counts
4. Cost Optimization
Use Spot/Preemptible instances for fault-tolerant workloads
Terminate idle clusters automatically
Use table properties to enable auto-compaction
Monitor cluster utilization metrics
Use Delta caching for frequently accessed data
5. Security and Governance
Use Unity Catalog for centralized governance
Implement fine-grained access control
Store secrets in Databricks secret scopes
Enable audit logging
Use service principals for production jobs
Anti-Patterns
1. Collecting Large DataFrames
# Bad: Collect large dataset to driver
large_df.collect() # OOM error# Good: Use actions that stay distributed
large_df.write.format("delta").save("/mnt/output")
2. Not Using Delta Lake Optimization
# Bad: Many small filesfor file in files:
df = spark.read.json(file)
df.write.format("delta").mode("append").save("/mnt/table")
# Good: Batch writes with optimization
df = spark.read.json("/mnt/source/*")
df.write.format("delta") \
.option("optimizeWrite", "true") \
.mode("append") \
.save("/mnt/table")
3. Inefficient Joins
# Bad: Join without broadcast hint
large_df.join(small_df, "key")
# Good: Broadcast small tablefrom pyspark.sql.functions import broadcast
large_df.join(broadcast(small_df), "key")
4. Not Using Partitioning
# Bad: No partitioning on large table
df.write.format("delta").save("/mnt/events")
# Good: Partition by date
df.write.format("delta") \
.partitionBy("date") \
.save("/mnt/events")