zondag 8 november 2026

Databricks series : Execute the job in Databricks (Part VI)

Introduction

This blogspost is the sixth in a series of blogposts about databricks. In these series I showed and will show several features of Databricks with easy to understand examples. In this blogpost we'll describe a more configurable ingestion framework. we'll replace the parameters in the job with a configrable file.

Currently, we have a Python script that reads a CSV file and writes it to a Delta table.

We want to extend this so that we no longer need to hardcode the source, target table, and loading strategy for each dataset within the Python code.

Instead, we will create a single configuration file that defines what needs to be done. The major advantage is that if you add a new entity tomorrow, you essentially only need to expand the configuration.

The new project structure

First, lets open the existing project, 'databricks-transfer', in Visual Studio Code. We are going to add a new directory called 'config'. We will add a file entities.json in there.

The project should now look like this:

databricks-transfer/
│
├── databricks.yml
│
├── resources/
│   └── transfer_job.yml
│
├── src/
│   ├── __init__.py
│   └── main.py
│
├── config/
│   └── entities.json
│
├── data/
│   ├── customers.csv
│   └── transactions.csv
│
├── requirements.txt
└── README.md


This file contains the configuration for all the entities we want to process.


{
  "customers": {
    "source": "/Volumes/main/demo/raw/customers.csv",
    "target": "main.demo.customers",
    "format": "csv",
    "mode": "overwrite"
  },
  "transactions": {
    "source": "/Volumes/main/demo/raw/transactions.csv",
    "target": "main.demo.transactions",
    "format": "csv",
    "mode": "append"
  },
  "products": {
    "source": "/Volumes/main/demo/raw/products.json",
    "target": "main.demo.products",
    "format": "json",
    "mode": "overwrite"
  }
}


Let’s take a look at what we are doing here.

  • customers. This is the name of the entity
  • source. The location of the source file
  • target. The target table in Unity Catalog
  • format. The file format
  • mode. The loading strategy

We have now defined three datasets. Note: 'products.json' is included as an example for a future expansion. You do not need to create that file yet. Why are we doing this? Suppose you want to add a fourth entity later, for example, 'suppliers'. In that case, you simply add an extra configuration block. You don’t need to write a new Python function.


Create a separate Python module for the configuration

Now, we will actually read the configuration. Open the 'src' directory. Create a new directory inside it:


src/
├── __init__.py
├── main.py
└── transfer/
    ├── __init__.py
    └── config_loader.py


Create the file src/transfer/config_loader.py. Add the following to it:


import json


def load_entity_config(config_path, entity):

    with open(config_path, "r") as file:
        config = json.load(file)

    if entity not in config:
        raise ValueError(
            f"Unknown entity: {entity}"
        )

    return config[entity]


What does this function do?

1. Opens the JSON configuration file.

2. Reads the content into a Python dictionary.

3. Looks up the requested entity.

4. Returns the corresponding configuration.

For example, when the 'customers' job is passed, we get:


{
    "source": "/Volumes/main/demo/raw/customers.csv",
    "target": "main.demo.customers",
    "format": "csv",
    "mode": "overwrite"
}


Create a separate Python module for data transfer

We will move the actual data transfer logic out of main.py. Create a new file: 'src/transfer/processor.py'. Add the following to it:


from pyspark.sql import SparkSession


def transfer_data(spark, config):

    source = config["source"]
    target = config["target"]
    file_format = config["format"]
    mode = config["mode"]

    print(f"Reading source: {source}")
    print(f"Target table: {target}")
    print(f"Format: {file_format}")
    print(f"Mode: {mode}")

    # Read source file
    df = (
        spark.read
        .format(file_format)
        .option("header", "true")
        .load(source)
    )

    # Write to Delta table
    (
        df.write
        .format("delta")
        .mode(mode)
        .saveAsTable(target)
    )

    print(f"Processed {df.count()} records")


We have now divided the responsibilities:

  • config_loader.py: determines what needs to be done.
  • processor.py: carries out the data transfer.

This is an important step in developing maintainable Python applications.


Modify main.py

Now, let’s bring everything together. Open src/main.py. Replace the existing content with:


import argparse
from pathlib import Path

from pyspark.sql import SparkSession

from transfer.config_loader import load_entity_config
from transfer.processor import transfer_data


def main():

    parser = argparse.ArgumentParser()

    parser.add_argument(
        "--entity",
        required=True
    )

    args = parser.parse_args()

    spark = SparkSession.builder.getOrCreate()

    # Configuration file location
    config_path = (
        Path(__file__).resolve().parents[1]
        / "config"
        / "entities.json"
    )

    # Load entity configuration
    config = load_entity_config(
        config_path,
        args.entity
    )

    # Execute data transfer
    transfer_data(spark, config)


if __name__ == "__main__":
    main()


What has changed? Previously, we provided three parameters:

entity
source_path
target_table


But now, we only provide:

entity


The rest is retrieved from entities.json. That is exactly what we want to achieve!


Ensure that DAB also deploys the configuration file

This is an important step that you must not overlook. Your Python code is located in `src`, while our JSON file is in `config`. We need to ensure that both directories are included in the deployment. Open `databricks.yml`. Modify its content:


bundle:
  name: databricks-transfer

include:
  - resources/*.yml

sync:
  include:
    - src/**
    - config/**
    - requirements.txt

targets:
  dev:
    default: true
    mode: development


Now, both the Python files and the JSON configuration file are synchronized.


Adjust the Databricks Job

Since we are now passing only the entity, we also need to update our Job configuration. Open: resources/transfer_job.yml and replace the contents with:


resources:
  jobs:
    transfer_job:

      name: python-data-transfer

      parameters:
        - name: entity
          default: customers

      tasks:
        - task_key: transfer_data

          spark_python_task:
            python_file: ../src/main.py

            parameters:
              - --entity
              - "{{job.parameters.entity}}"

          environment_key: default

      environments:
        - environment_key: default
          spec:
            environment_version: "2"


Our Job now has only one parameter: `entity`. When running it, you can choose from the following options: 'customers', 'transactions,  'products'. The Python code and the Job itself do not need to be modified for this.


Step 8 – Deploying to Databricks

Now we can deploy the project. Open the terminal in Visual Studio Code and navigate to the root of your project.  Execute:


databricks bundle validate -t dev


Resulting in : 




And if everything is right : 


databricks bundle deploy -t dev


Next, you can start the job:


> databricks bundle run transfer_job -t dev

Run URL: https://dbc-xxxxxx-d21b.cloud.databricks.com/jobs/846415909479637/runs/750647492568451?o=1134000616576115 2026-11-08 13:31:06 "[dev xxxxx] python-data-transfer" RUNNING 2026-11-08 13:31:47 "[dev xxxxx] python-data-transfer" TERMINATED SUCCESS Output: ======= Task transfer_data: Processing entity: customers ======= Task transfer_data: Processing entity: customers Successfully processed 4 records


The default value is customers.




Do you want to perform transactions? You can override the parameter when starting:

databricks bundle run transfer_job -t dev \
  --params entity=transactions


The parameter is then passed to main.py.




Important: ensure that the configuration files are actually available at the deployed path. In the example above, we use a path relative to main.py; therefore, the directory structure must be preserved during a DAB deployment.

The tables are now created : 






That's it!


Hennie

donderdag 5 november 2026

Databricks series : Execute the job in Databricks (Part V)

Introduction

This blogspost is the fifth in a series of blogposts. This blogpost describes the execution of the job in Databricks. In order to do that we need to do one thing and that is we need to place the files at the raw folder. Next is to execute job and as the final part we examine the results.

Create a volume in databricks

First we need to create a folder structure at the location :  /Volumes/main/demo/raw/


Open a notebook in Databricks and execute the following code :

%sql
CREATE CATALOG IF NOT EXISTS main;

CREATE SCHEMA IF NOT EXISTS main.demo;

CREATE VOLUME IF NOT EXISTS main.demo.raw;


This means : 

main                       ← Catalog

 └── demo            ← Schema

      └── raw          ← Volume


Upload the files to the location :






And here are the files stored at the locations. Everything is ready to execute the job.



Uitvoeren van de job

You can upload the files from our local data folder for this purpose.

Subsequently, we can run the same job twice.


entity = customers

source_path = /Volumes/main/demo/raw/customers.csv

target_table = main.demo.customers


entity = transactions

source_path  = /Volumes/main/demo/raw/transactions.csv

target_table = main.demo.transactions


The result should be: 

Job         Delta-table                 Records

Run 1 main.demo.customers 4

Run 2 main.demo.transactions 4


So, we have used one Python script and one Job for two different data streams.


Open de job and press on Run Now




The job is running now



Here you find information which code is executed in the job.



More information is available in the Job execution window




And in the unity catalog we see the following information.



Now execute the job with other parameters!



Enter the parameters and execute again.



And here information about the second run of the job



And this results in two tables with customer and transaction information.




Hennie

woensdag 4 november 2026

Databricks series : Deployment from Visual Studio Code (Part IV)

Introduction 

I've written a couple of blogposts about a small project to create a Databricks project. This blogpost is the fourth in the series. Now the fun part: we don’t have to manually create the Job in the Databricks interface. We’ll use the Databricks CLI for this!

Previous blogposts : 


Deploy the code

Open a terminal window in Visual Studio Code and authenticate with databricks auth login


 > databricks auth login --host https://dbc-xxxxxx-d21b.cloud.databricks.com/
--profile DBprofile


Validate the bundle

Next step is validate the code with databricks bundle validate


> databricks bundle validate

results in :

Name: DatabricksProject Target: dev Workspace: Host: https://dbc-xxxxxx-d21b.cloud.databricks.com User: xxxxxx@gmail.com Path: /Workspace/Users/xxxxx@gmail.com/.bundle/DatabricksProject/dev


Deploy the code

And deploy the code with databricks bundle deploy

> databricks bundle deploy

results in :

Uploading bundle files to /Workspace/Users/xxxxr@gmail.com/.bundle/DatabricksProject/dev/files... Created jobs.transfer_job Files: 1 uploaded, 0 deleted Resources: 1 created, 0 changed, 0 deleted, 0 unchanged


Databricks now deploys:

  • The Python code.
  • The job configuration.
  • The required project files.


Where is everything in Databricks?

In your Databricks Workspace, go to: Workspace → Users → your user → .bundle

There, you will typically find a structure such as:



Job-configuration

The Job itself is not necessarily found as a YAML file within the Workspace.

Go to: Workflows → Jobs & Pipelines

Search for: python-data-transfer

There, you can view:

  • The Job configuration.
  • The configured parameters.
  • The Python Script Task.
  • The execution history.
  • The logs and results.


The YAML configuration remains part of your local DAB project in Visual Studio Code. Databricks uses that configuration to create or update the Job.



So that's it. The code is deployed to Databricks with DAB


Hennie

dinsdag 3 november 2026

Databricks series : Setting up a Databricks project in Visual Studio Code (part III)

Introduction

In this blogpost I'll describe the Visual Studio Project in more detail. This blogpost is one in a series of blogposts. Here are the previous blogposts : 


Project structure

Lets create a project structure where we can store our code and also the data files. I've created the following structure in Visual studio Code :

databricks-transfer/
│
├── databricks.yml
├── resources/
│   └── transfer_job.yml
│
├── src/
│   ├── __init__.py
│   └── main.py
│
├── data/
│   ├── customers.csv
│   └── transactions.csv
│
├── requirements.txt
└── README.md


What is the function of the different folders?





Some test data


For this blogseries, I've created a couple of testfiles with help of ChatGPT :


customers.csv




transactions.csv




Python code

The application performs three tasks:

  1. Receives parameters from the Databricks Job.

  2. Reads the specified CSV file using Spark.

  3. Writes the data to a Delta table.


The advantage is that the Python code is independent of the specific dataset being processed.


import argparse
from pyspark.sql import SparkSession


def main():

    parser = argparse.ArgumentParser()

    parser.add_argument("--entity", required=True)
    parser.add_argument("--source-path", required=True)
    parser.add_argument("--target-table", required=True)

    args = parser.parse_args()

    spark = SparkSession.builder.getOrCreate()

    print(f"Processing entity: {args.entity}")

    df = (
        spark.read
        .option("header", "true")
        .option("inferSchema", "true")
        .csv(args.source_path)
    )

    (
        df.write
        .format("delta")
        .mode("overwrite")
        .saveAsTable(args.target_table)
    )

    print(f"Successfully processed {df.count()} records")


if __name__ == "__main__":
    main()


DAB

DAB will start with databricks.yml file. This is the content of the databricks.yml:

bundle:
  name: DatabricksProject

include:
  - resources/*.yml

targets:
  dev:
    mode: development
    default: true
    workspace:
      host: https://dbc-xxxxxxx.cloud.databricks.com


This is an example of a serverless Python Job. The environment is linked to the task via environment_key. The Job has three parameters:



Create a transfer_job.yml in the resources folder :

resources:
  jobs:
    transfer_job:

      name: python-data-transfer

      parameters:
        - name: entity
          default: customers

        - name: source_path
          default: /Volumes/main/demo/raw/customers.csv

        - name: target_table
          default: main.demo.customers

      tasks:
        - task_key: transfer_data

          spark_python_task:
            python_file: ../src/main.py

            parameters:
              - --entity
              - "{{job.parameters.entity}}"
              - --source-path
              - "{{job.parameters.source_path}}"
              - --target-table
              - "{{job.parameters.target_table}}"

          environment_key: default

      environments:
        - environment_key: default
          spec:
            environment_version: "2"


The Job passes these parameters to main.py. Pay special attention to:"{{job.parameters.entity}}"

This is a dynamic reference to a Job parameter. Databricks populates this value when the Job is executed. This means we do not need to modify our Python code when we want to process a different dataset. It is also possible to perform an explicit sync action.


bundle:
  name: DatabricksProject

include:
  - resources/*.yml

sync:
  include:
    - src/**
    - requirements.txt
    
targets:
  dev:
    mode: development
    default: true
    workspace:
      host: https://dbc-xxxxxx-d21b.cloud.databricks.com

  ## Optionally, there could be 'staging' or 'prod' targets here.
  #
  # prod:
  #   workspace:
  #     host: https://dbc-xxxxxx-d21b.cloud.databricks.com


This allows you to specify which project files you want to synchronize. We deliberately exclude the `data/` directory: our CSV files are ultimately stored in a Unity Catalog Volume.


Hennie

maandag 2 november 2026

Databricks series : setting up a connection to Databricks from local IDE (Part II)

Introduction

This is the second blogpost in a series about setting up an environment and perform a small project in Databricks. The first blogpost was about the installation of Databricks local IDE and this is the second blogpost in the series. In this blogpost we'll continue setting up the environment and make a connection to the workspace in Databricks.


This is the first blogpost in the series : Databricks series : Starting a new python project in Visual Studio Code (Part I)


These are the steps I've taken to setup the connection :

  • Open the Databricks sidebar in Visual Studio Code and configure a new connection.
  • Select your Databricks Workspace.
  • Configure authentication, for example, using OAuth.
  • Sign in through your browser.
  • Select the desired compute resource.
  • Setup the Python environment.

 

Create a configuration

First you need to setup a configuration in Visual Studio Code.



Fill the URL to the Databricks environment.



And select OAUTH (in my case)



And give the profile a proper name. I called it DBProfile.



Sign in with your account to Databricks.



A verification code is necessary to enter and if all is verified then you are authenticated.




And in Visual Studio Code you see the following configuration settings:



And there is more information about my Databricks Workspace there.




Next step is to select the compute. The option is to select Serverless and this is fine for now.


And I selected v5 as the version for the serverless compute.


Next there is the set up for the Python environment.




But I ran into an error. uv was not installed yet. 




I tried to install with Winget but that didn't succeed.

winget install --id=astral-sh.uv -e





But ran in an error because uv was not recognized as a valid command. 




I think it has something to do with the PATH variable in Windows. On Stackoverflow I found a script that I used to install in a terminal in Visual Studio Code: https://stackoverflow.com/questions/79474930/uv-command-not-found-in-visual-studio-code-on-windows

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"



And in the output tab of Visual Studio it states now that the full intstallation of Python for Databricks  Connect is succeeded. 



Once configured, we now can work with our Databricks environment directly from Visual Studio Code.




Final thoughts

Quite some steps to setup the local environment for connecting to Databricks. Up to the next blogpost!


Hennie