Lakebench
Run a real data workload through a composable lakehouse architecture on Kubernetes, and get evidence of how it behaved.
Deploy a complete lakehouse stack from a single YAML, generate a workload corpus, run its pipeline and queries at any scale, and get a scorecard that records exactly what produced it, including a fingerprint of each query's result, so a reader can check that two runs returned the same answers before comparing their numbers.
Why Lakebench?
- Compare stacks. Swap catalogs (Hive, Polaris), query engines (Trino, Spark Thrift, DuckDB), and table formats (Iceberg, Delta) -- same data, same queries, different architecture. Each run's report records a result fingerprint per query, so you can see that two runs returned the same answers before you compare their performance.
- Test at scale. Run the same workload at 10 GB, 100 GB, and 1 TB to find where throughput plateaus or resources saturate on your hardware.
- Measure freshness. Continuous mode keeps data arriving through the pipeline and benchmarks query performance under ongoing ingest load.
Workloads
Lakebench ships two workload schemas. The stack is the same either way; the schema flag routes datagen and the pipeline scripts.
- Customer 360 (default). Retail interactions from ~8 channels flow
through bronze / silver / gold into an executive dashboard and the
8-query analytical benchmark.
workload.schema: customer360. - Financial crime (AML). pacs.008 wire messages from a frozen
generator (
datagen-v2-rs-0.3) flow through bronze / silver / gold. Nine detection rules, including a fuzzy sanctions and PEP screen against a synthetic, dated watchlist, are scored for recall and precision against planted typologies (structuring, round-tripping, layering, dormant reactivation, high-risk corridors and others) byspark/scripts/score_financial.py, whichlakebench runinvokes inline. A pre-registered reference model (the fidelity gate) and a band leakage report ship separately aslakebench financial reference-score; they diagnose whether a rule could read high recall from a label proxy, and they are not run bylakebench run. Iceberg recipes only.workload.schema: financial. See AML Scoring for what precision and recall measure here vs what an AML ops team cares about.
Quick Start
pip install lakebench-k8s
Pre-built binaries (no Python required) are available on GitHub Releases.
lakebench init # writes lakebench.yaml (--workload financial for AML): set its S3 endpoint, export the two key variables it names
lakebench admin install --component all lakebench.yaml # once per cluster (cluster admin)
lakebench plan lakebench.yaml # what the run needs and whether the cluster has room; changes nothing
lakebench run lakebench.yaml --generate --yes # deploy + generate + pipeline + benchmark
lakebench report lakebench.yaml # view scorecard
lakebench destroy lakebench.yaml # tear down what this deployment owns (asks first; --yes to skip)
--yes lets run deploy the namespace and components when they do not
exist yet; without it run stops and asks you to run lakebench deploy
first. The Spark Operator, the Stackable operators (Hive recipes), the scratch
StorageClass and the observability stack are shared cluster infrastructure:
deploy only checks them, and a cluster admin installs them once with
lakebench admin install --component all lakebench.yaml (see
Getting Started).
Minimum config:
# lakebench.yaml, as `lakebench init` writes it
name: lb-alice-7f3c # names the namespace and the buckets
recipe: polaris-iceberg-spark-trino
workload:
schema: customer360
datagen:
scale: 1 # 1 = ~10 GB, 10 = ~100 GB, 100 = ~1 TB
platform:
storage:
s3:
endpoint: http://s3.example.com:80
access_key: "${LAKEBENCH_S3_ACCESS_KEY}"
secret_key: "${LAKEBENCH_S3_SECRET_KEY}"
The name is required by every command that changes data (deploy,
generate, run and the rest); a config without one is refused with the
name to add. Buckets default to <name>-bronze, <name>-silver
and <name>-gold, so they are unique on stores where bucket names are
global (FlashBlade, AWS S3). A config with no recipe: (or recipe: default)
still resolves to hive-iceberg-spark-trino with a deprecation note; v1.8
requires the recipe. A component written against the recipe (say
catalog.type: hive under a Polaris recipe) is refused at load.
Override anything in the nested YAML:
# lakebench.yaml (with overrides)
name: flashblade-polaris
recipe: polaris-iceberg-spark-trino
images:
spark: apache/spark:4.1.1-python3
platform:
storage:
s3:
endpoint: http://10.0.1.50:80
access_key: "${S3_ACCESS_KEY}" # env var substitution; quote it
secret_key: "${S3_SECRET_KEY}"
architecture:
pipeline:
mode: batch
workload:
datagen:
scale: 50
The flat top-level spellings (endpoint:, scale: and the others in
Configuration)
still load, with a deprecation note naming the nested key.
Polaris needs no client secret in the config: deploy generates one per
deployment and stores it in the namespace.
Eleven recipes are available -- see Recipes
for the full list. Support is judged per workload x recipe x mode:
supported means a live run on the release tree validated it end to end,
unverified means it is valid but not release-validated, and
unsupported is refused before a run
(rules).
Every run records its state in metrics.json. As computed by this release:
| Recipe | Customer 360 batch | Customer 360 continuous | AML (financial) batch | AML (financial) continuous |
|---|---|---|---|---|
hive-delta-spark-none |
unverified [1] | unverified [1] | unsupported | unsupported |
hive-delta-spark-thrift |
unverified [2] | unverified [1] | unsupported | unsupported |
hive-delta-spark-trino |
unverified [2] | unverified [2] | unsupported | unsupported |
hive-iceberg-spark-duckdb |
unverified [2] | unverified [1] | unverified [1] | unverified [1] |
hive-iceberg-spark-none |
unverified [2] | unverified [1] | unverified [1] | unverified [1] |
hive-iceberg-spark-thrift |
unverified [2] | unverified [1] | unverified [1] | unverified [1] |
hive-iceberg-spark-trino |
unverified [2] | unverified [2] | unverified [2] | unverified [2] |
polaris-iceberg-spark-duckdb |
unverified [2] | unverified [1] | unverified [1] | unverified [1] |
polaris-iceberg-spark-none |
unverified [1] | unverified [1] | unverified [1] | unverified [1] |
polaris-iceberg-spark-thrift |
unverified [2] | unverified [1] | unverified [1] | unverified [1] |
polaris-iceberg-spark-trino |
unverified [2] | unverified [1] | unverified [2] | unverified [2] |
- [1] unverified: not in this release's validation matrix.
- [2] unverified: in this release's validation matrix; no validation run is listed yet.
- unsupported, refused at config load: AML (financial) on
hive-delta-spark-none,hive-delta-spark-thrift,hive-delta-spark-trino. The financial (AML) workload supports table_format iceberg, not delta. Its stage scripts and table DDL are written for iceberg only, so this combination would not run the workload it names. Use an iceberg recipe (for example recipe: polaris-iceberg-spark-trino), or with no recipe set architecture.table_format.type to iceberg. - Any catalog, table format and query engine combination that is not a recipe above is refused at config load for every workload.
- A supported cell names the Spark minor and table format version its validation runs used; the same cell on any other Spark minor or format version is unverified. Spark 3.5 is unverified and gets no v1.7 features.
- AML (financial) continuous: AML continuous runs detection rules W2, W3, W4, W17 each tick and records W1, W5, W6, W7, W8 as not run. Its results depend on when detection ran relative to arrival, so no end-of-run result check is recorded.
Compare two configurations by running each and reading the two reports side by side:
lakebench deploy config-hive.yaml && lakebench run config-hive.yaml
lakebench deploy config-polaris.yaml && lakebench run config-polaris.yaml
lakebench report config-hive.yaml
lakebench report config-polaris.yaml
report prints each run's scorecard and the path of the HTML report the run
wrote. Each HTML report's Experiment section states the corpus, datagen image, components,
maintenance, the stages and rules that ran, a result fingerprint per
benchmark query and, for AML batch runs, the alert set. Compare performance
only when the corpus, the result fingerprints and the alert set match:
a difference means the two stacks returned different answers. A number bounded by a Lakebench cap is labelled as such.
For all recipes, see examples/, lakebench config recipes,
or lakebench init --recipe <name>.
What You Get
Each lakebench run prints a scorecard summary (per-stage seconds and the
run's scores) and writes lakebench-output/runs/run-<id>/report.html with
per-query latencies, bottleneck analysis and, when observability is enabled,
pod-level CPU, memory and S3 I/O. lakebench report prints the summary and
points at the HTML; --render writes a fresh copy. Every run's
metrics.json carries an experiment block: workload and generator
version, seed, recipe and component versions, scale, mode, the maintenance
that actually ran, the Lakebench-imposed limits that applied and whether
they bound, the support state, and a fingerprint of each query's result.
Upgrading from 1.6: every change that can break a 1.6 config, command line or script, with what to do, is in UPGRADING-1.7.md; redeploy each deployment once after upgrading. Numbers from 1.5 and earlier are not comparable with 1.7: no Iceberg snapshot expiry or Delta VACUUM ran before 1.6, and the v1.7 datagen image changes the corpus. See the CHANGELOG.
How It Works
┌──────────────────────────────────┐
│ lakebench.yaml │
└────────────┬─────────────────────┘
│
┌────────────▼─────────────────────┐
│ deploy (Kubernetes namespace, │
│ S3 secrets, PostgreSQL, catalog, │
│ query engine, observability) │
└────────────┬─────────────────────┘
│
Raw Parquet ──► Bronze (validate) ──► Silver (enrich) ──► Gold (aggregate)
S3 Spark Spark Spark
│
┌───────────▼──────────┐
│ 8-query benchmark │
│ (Trino / DuckDB / │
│ Spark Thrift) │
└──────────────────────┘
Prerequisites
kubectlandhelmon PATH- Kubernetes 1.26+ with room for the minimum below: what must fit at once,
for the default recipe (
hive-iceberg-spark-trino), from the sizing function behindlakebench config show,config recommendand theruncapacity preflight. Batch datagen pods that do not fit wait their turn, so the batch minimum is the Spark peak plus the always-on pods. See Getting Started for what each figure is built from.lakebench runfails fast if the cluster is too small.
| Workload | Mode | Scale | Minimum CPU | Minimum RAM | Scratch PVC (if enabled) | Largest pod |
|---|---|---|---|---|---|---|
| Customer 360 | batch | 1 | 41 cores | 544 GB | 2,400 Gi | 8 cores / 60 GB |
| Customer 360 | batch | 10 | 48 cores | 572 GB | 2,400 Gi | 8 cores / 60 GB |
| Customer 360 | batch | 100 | 114 cores | 1,340 GB | 5,400 Gi | 8 cores / 60 GB |
| Customer 360 | continuous | 1 | 59 cores | 309 GB | 640 Gi | 8 cores / 40 GB |
| Customer 360 | continuous | 10 | 82 cores | 345 GB | 640 Gi | 8 cores / 40 GB |
| Customer 360 | continuous | 100 | 202 cores | 955 GB | 1,700 Gi | 8 cores / 48 GB |
| AML | batch | 1 | 41 cores | 544 GB | 2,400 Gi | 8 cores / 60 GB |
| AML | batch | 10 | 48 cores | 572 GB | 2,400 Gi | 8 cores / 60 GB |
| AML | batch | 100 | 114 cores | 1,340 GB | 5,500 Gi | 8 cores / 60 GB |
| AML | continuous | 1 | 139 cores | 1,023 GB | 2,300 Gi | 8 cores / 40 GB |
| AML | continuous | 10 | 162 cores | 1,065 GB | 2,300 Gi | 8 cores / 40 GB |
| AML | continuous | 100 | 340 cores | 2,253 GB | 4,660 Gi | 8 cores / 48 GB |
- S3-compatible object storage. FlashBlade and Garage are validated; others are
expected to work. Run
lakebench config storageto check yours. See Storage Backends. - Kubeflow Spark Operator 2.5.1+,
installed once per cluster with
lakebench admin install --component spark-operator.deployadds its namespace to the operator's watch list itself, under the cluster lock; do not editspark.jobNamespacesby hand. - Stackable Hive Operator for Hive recipes (not needed for Polaris)
Commands
| Command | Description |
|---|---|
init |
Generate a starter config file; --from OLD converts an older one |
config validate |
Check config and cluster connectivity |
config storage |
Check the S3 backend supports what lakebench needs |
config show |
Show the resolved configuration and its peak requested resources |
plan |
Show what a config needs (components, sizing, prerequisites) and check the cluster has room; read-only |
deploy |
Deploy all infrastructure components |
generate |
Generate synthetic data at the configured scale |
run |
Execute the medallion pipeline and benchmark |
benchmark |
Run the workload's query benchmark standalone |
query |
Execute ad-hoc SQL against the active engine |
status |
Show deployment status |
report |
Show a run's scorecard in the terminal (--format for the stage matrix, --render for HTML) |
config recommend |
Recommend a scale factor for the connected cluster |
config recipes |
List recipes and their support state per workload and mode |
admin |
Cluster-admin setup and repair: install --component, doctor, status, repair-operator, release-lock, migrate-deployment, reclaim-bucket (install-spark-operator and install-scratch-storage-class are aliases of install --component) |
financial |
AML operator actions (score, reference-score, replay, reproduce) |
reproduce |
Record or verify a reproduction package from a run |
destroy |
Tear down the resources this deployment owns |
See CLI Reference for flags and options.
Component Versions
| Component | Version |
|---|---|
| Apache Spark | 3.5.x, 4.0.x (default on the Polaris recipes and hive-delta-spark-thrift: 4.0.2), 4.1.x (default on the Hive recipes: 4.1.1; 4.2 not supported) |
| Spark Operator | 2.5.1 (Kubeflow) |
| Apache Iceberg | 1.11.0 (1.10.1 with Spark 3.5.4 on its Java 11 image, and in local mode) |
| Delta Lake | 4.0.0 / 4.1.0 (auto, by Spark version) |
| Hive Metastore | 3.1.3 (Stackable 25.7.0) |
| Apache Polaris | 1.6.0 |
| Trino | 483 |
| DuckDB | 1.5.5 (Python 3.11 image) |
| PostgreSQL | 16, 17, 18 |
All versions are overridable in the YAML config. See Supported Components.
Documentation
- Getting Started -- prerequisites, install, first run
- Configuration -- full YAML reference
- Recipes -- catalog + format + engine combinations
- Compatibility Matrix -- Spark, Iceberg, and Delta version support
- Running Pipelines -- batch and continuous modes
- Benchmarking -- scorecard and query benchmark
- AML Scoring -- financial-crime / AML workload: rule recall, reference detector, leakage gate
- Architecture -- system design
- Storage Backends -- validated S3 backends and conformance checks
- Troubleshooting -- common errors and fixes
License
Apache 2.0
Metadata
Release files for lakebench-k8s 1.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| lakebench_k8s-1.7.0.tar.gz | 2.1 MB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lakebench_k8s-1.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 3.8 MB
Release files / lakebench_k8s-1.7.0.tar.gz
| Download URL | lakebench_k8s-1.7.0.tar.gz |
|---|---|
| Size | 2.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fa874ee0e8f4206583ac1dc82c3dca2a73bf5261721f932a719c52b1cc48f260
|
|
BLAKE2b-256 checksum How to use checksums |
14494f282f7cac602a571a3a271012635a31c3e90b441431a25bb2c635fc1855
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / lakebench_k8s-1.7.0-py3-none-any.whl
| Download URL | lakebench_k8s-1.7.0-py3-none-any.whl |
|---|---|
| Size | 1.7 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c8b81fb901014b81d9a4dddccd314105b79b9e52312b734fef8ba0f164eb0ede
|
|
BLAKE2b-256 checksum How to use checksums |
d20a0e105198a79816d146eb4aef7715e4b468cc9bd8e6cdad8f747598855267
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logSecurity for lakebench-k8s 1.7.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for lakebench_k8s-1.7.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.