Skip to content

How to use partitioned and incremental datasets

This guide shows how to configure and use PartitionedDataset and IncrementalDataset. For the concepts behind partition IDs, credentials, lazy saving, and checkpoints, see the concept page.

How to define a PartitionedDataset

You can use a PartitionedDataset in catalog.yml like any other dataset definition:

# conf/base/catalog.yml

my_partitioned_dataset:
  type: partitions.PartitionedDataset
  path: s3://my-bucket-name/path/to/folder  # path to the location of partitions
  dataset: pandas.CSVDataset  # shorthand notation for the dataset which will handle individual partitions
  credentials: my_credentials
  load_args:
    load_arg1: value1
    load_arg2: value2

Note

Like any other dataset, PartitionedDataset can also be instantiated programmatically in Python.

from kedro_datasets.pandas import CSVDataset
from kedro_datasets.partitions import PartitionedDataset

my_credentials = {...}  # credentials dictionary

my_partitioned_dataset = PartitionedDataset(
    path="s3://my-bucket-name/path/to/folder",
    dataset=CSVDataset,
    credentials=my_credentials,
    load_args={"load_arg1": "value1", "load_arg2": "value2"},
)

If you need more granular configuration of the underlying dataset, provide its definition in full:

# conf/base/catalog.yml

my_partitioned_dataset:
  type: partitions.PartitionedDataset
  path: s3://my-bucket-name/path/to/folder
  dataset:  # full dataset config notation
    type: pandas.CSVDataset
    load_args:
      delimiter: ","
    save_args:
      index: false
  credentials: my_credentials
  load_args:
    load_arg1: value1
    load_arg2: value2
  filepath_arg: filepath  # the argument of the dataset to pass the filepath to
  filename_suffix: ".csv"

For the full set of PartitionedDataset arguments and the rules around shorthand and full dataset notation, see the concept page.

How partitioned dataset credentials interact

The table below covers every combination of top-level credentials on PartitionedDataset and credentials defined on the underlying dataset:

Top-level credentials Underlying dataset credentials Example PartitionedDataset definition Description
Undefined Undefined PartitionedDataset(path="s3://bucket-name/path/to/folder", dataset="pandas.CSVDataset") Credentials are not passed to the underlying dataset or the filesystem.
Undefined Specified PartitionedDataset(path="s3://bucket-name/path/to/folder", dataset={"type": "pandas.CSVDataset", "credentials": {"secret": True}}) Underlying dataset credentials are passed to the CSVDataset constructor; the filesystem is instantiated without credentials.
Specified Undefined PartitionedDataset(path="s3://bucket-name/path/to/folder", dataset="pandas.CSVDataset", credentials={"secret": True}) Top-level credentials are passed to the underlying CSVDataset constructor and the filesystem.
Specified None PartitionedDataset(path="s3://bucket-name/path/to/folder", dataset={"type": "pandas.CSVDataset", "credentials": None}, credentials={"dataset_secret": True}) Top-level credentials are passed to the filesystem; CSVDataset is instantiated without credentials. This is how you stop the top-level credentials from propagating into the dataset config.
Specified Specified PartitionedDataset(path="s3://bucket-name/path/to/folder", dataset={"type": "pandas.CSVDataset", "credentials": {"dataset_secret": True}}, credentials={"secret": True}) Top-level credentials are passed to the filesystem; underlying dataset credentials are passed to the CSVDataset constructor.

How to load partitions in a node

Assume that the Kedro pipeline you are working with contains the following node:

from kedro.pipeline import Node

Node(concat_partitions, inputs="my_partitioned_dataset", outputs="concatenated_result")

The underlying node function concat_partitions might look like this:

from typing import Any, Callable, Dict
import pandas as pd


def concat_partitions(partitioned_input: Dict[str, Callable[[], Any]]) -> pd.DataFrame:
    """Concatenate input partitions into one pandas DataFrame.

    Args:
        partitioned_input: A dictionary with partition ids as keys and load functions as values.

    Returns:
        Pandas DataFrame representing a concatenation of all loaded partitions.
    """
    result = pd.DataFrame()

    for partition_key, partition_load_func in sorted(partitioned_input.items()):
        partition_data = partition_load_func()  # load the actual partition data
        # concat with existing result
        result = pd.concat([result, partition_data], ignore_index=True, sort=True)

    return result

PartitionedDataset does not load partition data on its own — the node decides which partitions to load and how to process them. See How partitions are identified for the rules that determine partition IDs.

How to save partitions from a node

PartitionedDataset also supports save operations. Assume the following configuration:

# conf/base/catalog.yml

new_partitioned_dataset:
  type: partitions.PartitionedDataset
  path: s3://my-bucket-name
  dataset: pandas.CSVDataset
  filename_suffix: ".csv"
  save_lazily: True

And the following node definition:

from kedro.pipeline import Node

Node(create_partitions, inputs=None, outputs="new_partitioned_dataset")

The underlying node function returns a dictionary keyed by partition IDs:

from typing import Any, Dict
import pandas as pd


def create_partitions() -> Dict[str, Any]:
    """Create new partitions and save using PartitionedDataset.

    Returns:
        Dictionary with the partitions to create.
    """
    return {
        # create a file "s3://my-bucket-name/part/foo.csv"
        "part/foo": pd.DataFrame({"data": [1, 2]}),
        # create a file "s3://my-bucket-name/part/bar.csv.csv"
        "part/bar.csv": pd.DataFrame({"data": [3, 4]}),
    }

Note

Writing to an existing partition may overwrite its data if the underlying dataset implementation does not handle this case. Add checks to ensure no existing data is lost. One safeguard is to use partition IDs with a high chance of uniqueness, such as the current timestamp.

How to control lazy saving

To use lazy saving, return Callable types in the dictionary:

from typing import Any, Dict, Callable
import pandas as pd


def create_partitions() -> Dict[str, Callable[[], Any]]:
    """Create new partitions and save using PartitionedDataset.

    Returns:
        Dictionary of the partitions to create to a function that creates them.
    """
    return {
        # create a file "s3://my-bucket-name/part/foo.csv"
        "part/foo": lambda: pd.DataFrame({"data": [1, 2]}),
        # create a file "s3://my-bucket-name/part/bar.csv"
        "part/bar": lambda: pd.DataFrame({"data": [3, 4]}),
    }

Note

Lazy saving is enabled by default. When a Callable is provided, the dataset is written after the after_node_run hook finishes.

To disable lazy saving, set save_lazily: False:

# conf/base/catalog.yml

new_partitioned_dataset:
  type: partitions.PartitionedDataset
  path: s3://my-bucket-name
  dataset: pandas.CSVDataset
  filename_suffix: ".csv"
  save_lazily: False

Note

If you create lambdas in a list/dictionary comprehension or a for loop, be careful when referencing variables defined outside the scope of the lambdas. See the Python Programming FAQ for an explanation of how this can result in unexpected values being returned from the lambdas.

How to confirm incremental datasets

Partitioned dataset checkpoint update is triggered by an explicit confirms instruction on one of the downstream nodes. The simplest case is to confirm within the same node that processes the partitioned dataset:

from kedro.pipeline import Node

# process and then confirm `IncrementalDataset` within the same node
Node(
    process_partitions,
    inputs="my_partitioned_dataset",
    outputs="my_processed_dataset",
    confirms="my_partitioned_dataset",
)

You can also defer confirmation to a downstream node to run additional validation before treating the loaded partitions as processed:

from kedro.pipeline import Node, Pipeline

Pipeline(
    [
        Node(
            func=process_partitions,
            inputs="my_partitioned_dataset",
            outputs="my_processed_dataset",
        ),
        # do something else
        Node(
            func=confirm_partitions,
            # note that the node may not require 'my_partitioned_dataset' as an input
            inputs="my_processed_dataset",
            outputs=None,
            confirms="my_partitioned_dataset",
        ),
        # ...
        Node(
            func=do_something_else_with_partitions,
            # will return the same partitions even though they were already confirmed
            inputs=["my_partitioned_dataset", "my_processed_dataset"],
            outputs=None,
        ),
    ]
)

For the rules that govern when confirmation takes effect, see the confirmation step.

How to configure incremental dataset checkpoints

IncrementalDataset does not require explicit configuration of the checkpoint unless you need to deviate from the defaults. To override the checkpoint configuration, add a checkpoint key containing the valid dataset configuration. This is useful when the pipeline has read access to the location of partitions but no write permissions (or when write operations are undesirable). The checkpoint key also supports partial config updates, where a subset of checkpoint attributes is overwritten while the defaults are kept for the rest:

my_partitioned_dataset:
  type: partitions.IncrementalDataset
  path: s3://my-bucket-name/path/to/folder
  dataset: pandas.CSVDataset
  checkpoint:
    # update the filepath and load_args, but keep the dataset type unchanged
    filepath: gcs://other-bucket/CHECKPOINT
    load_args:
      k1: v1

To use a custom comparison function (for example, for windowed loading of the last calendar month):

my_partitioned_dataset:
  type: partitions.IncrementalDataset
  path: s3://my-bucket-name/path/to/folder
  dataset: pandas.CSVDataset
  checkpoint:
    comparison_func: my_module.path.to.custom_comparison_function  # the path must be importable

To force a specific checkpoint value (for example, to reprocess partitions from a known starting point):

my_partitioned_dataset:
  type: partitions.IncrementalDataset
  path: s3://my-bucket-name/path/to/folder
  dataset: pandas.CSVDataset
  checkpoint:
    force_checkpoint: 2020-01-01/data.csv

Note

Specifying force_checkpoint is also supported through shorthand notation:

my_partitioned_dataset:
  type: partitions.IncrementalDataset
  path: s3://my-bucket-name/path/to/folder
  dataset: pandas.CSVDataset
  checkpoint: 2020-01-01/data.csv

Note

To force the partitioned dataset to load all available partitions, set checkpoint to an empty string:

my_partitioned_dataset:
  type: partitions.IncrementalDataset
  path: s3://my-bucket-name/path/to/folder
  dataset: pandas.CSVDataset
  checkpoint: ""