Skip to content

Add Dask - #1053

Merged
alexey-milovidov merged 3 commits into
mainfrom
add-dask
Jul 24, 2026
Merged

Add Dask#1053
alexey-milovidov merged 3 commits into
mainfrom
add-dask

Conversation

@alexey-milovidov

Copy link
Copy Markdown
Member

Closes #892.

Adds a Dask entry. Dask is "pandas in parallel", so this mirrors the existing pandas port: a small FastAPI server wraps a Dask DataFrame behind the standard install/start/check/stop/load/query/data-size interface, and queries.sql holds one Python expression per line that the server eval()s — exactly the pattern used by pandas and polars-dataframe.

Design

  • Parallelism: a dask.distributed.LocalCluster of worker processes gives real multi-core execution. The frame is persist()ed into cluster memory (and wait()ed on) so load time is comparable to the pandas/polars in-memory model. BENCH_DURABLE=no, so the harness reloads before each cold query and rolls that into the cold try, as with the other in-memory dataframe systems.
  • Dataset: reads the partitioned parquet (hits_0..99.parquet) — one partition per file is Dask's natural layout (BENCH_DOWNLOAD_SCRIPT=download-hits-parquet-partitioned).
  • Lazy execution: the server materialises each result with dask.compute() and times eval() + compute() together (mirroring pandas, where eval() does all the work). dask.compute() recurses into tuples/lists, so the tuple queries (3, 7) and the 90-sum query (30) compute in one pass.

Query translation

Queries stay close to the pandas port, diverging only where Dask's API does:

  • Q10, Q23 (COUNT(DISTINCT) alongside other aggregates): Dask's built-in groupby.agg has no nunique, so these use Dask's documented custom nunique aggregation.
  • Q39–Q43 (LIMIT … OFFSET): Dask has no positional iloc, so these take the small top-N with nlargest and slice in pandas after compute() (SQL-faithful, matching how polars-dataframe does it — not the pandas port's nlargest(10).iloc[1000:] quirk that returns empty).
  • Q8, Q26, Q27: Dask Series has no sort_values, so these use nlargest / frame sort_values.

Validation

All 43 queries were validated against a synthetic dataset under both the threaded scheduler and a real distributed LocalCluster, and end-to-end through the HTTP server. Verified that cluster teardown on shutdown leaves no orphaned worker processes across the harness's repeated stop/start/reload cycles. Real timings still need a run on a benchmark machine (aarch64 dev box can't produce the x86 result set).

🤖 Generated with Claude Code

Implements #892.

Dask is "pandas in parallel", so this mirrors the pandas port: a FastAPI
server wraps a Dask DataFrame behind the install/start/check/stop/load/
query/data-size interface, and queries.sql holds one Python expression
per line (eval()'d by the server), just like pandas/polars.

Dask-specific choices:
  - Uses a local cluster of worker processes (dask.distributed.LocalCluster)
    for real multi-core parallelism; the frame is persisted in cluster
    memory so load time is comparable to the pandas/polars in-memory model.
  - Reads the partitioned dataset (hits_0..99.parquet) — one partition per
    file is Dask's natural layout.
  - Operations are lazy, so the server materialises each result with
    dask.compute() and rolls that into the query timing.
  - Queries are close to the pandas port, diverging only where Dask's API
    does: COUNT(DISTINCT) combined with other aggregates (Q10, Q23) uses
    Dask's documented custom nunique aggregation, LIMIT/OFFSET tails
    (Q39-43) compute the small top-N to pandas then slice (Dask has no
    positional iloc), and Q8/Q26/Q27 use nlargest/sort_values since Dask
    Series lacks sort_values.

All 43 queries validated against a synthetic dataset both with the
threaded scheduler and a real distributed LocalCluster, and end-to-end
through the HTTP server; cluster teardown on shutdown leaves no orphaned
workers across the harness's stop/start/reload cycles.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexey-milovidov alexey-milovidov added the machine:c6a.metal PR benchmark machine override: c6a.metal (192 vCPU, 384 GB, AMD) label Jul 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Results for dask are ready for: c6a.metal.
The result files are committed as af0df52.

Logs:

@alexey-milovidov alexey-milovidov added machine:all PR benchmark on every machine type and removed machine:c6a.metal PR benchmark machine override: c6a.metal (192 vCPU, 384 GB, AMD) labels Jul 23, 2026
@alexey-milovidov alexey-milovidov self-assigned this Jul 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

The run of dask on c6a.4xlarge did not produce results.
The run of dask on c8g.4xlarge did not produce results.

Logs:

@github-actions

Copy link
Copy Markdown
Contributor

Results for dask are ready for: c6a.metal, c7a.metal-48xl, c8g.metal-48xl.
The result files are committed as d4a9521.

Logs:

@github-actions

Copy link
Copy Markdown
Contributor

The run of dask on c6a.2xlarge did not produce results.
The run of dask on c6a.large did not produce results.
The run of dask on c6a.xlarge did not produce results.
The run of dask on t3a.small did not produce results.

Logs:

@alexey-milovidov
alexey-milovidov merged commit 88f37e4 into main Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

machine:all PR benchmark on every machine type

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Dask

1 participant