Krishiv

Spark-compatible compute. Written in Rust.

Krishiv Engine · available in 0.2.0

The Spark-compatible engine without the JVM.

Write the SQL and DataFrame code you already know. Krishiv runs it in your process, over Arrow, on a vectorised engine written in Rust.

QuickstartDocumentation

What you can do today

  • SQL and DataFrames

    A PySpark-style session with spark.sql, spark.read.parquet, filters, joins, aggregates and windows, following Spark's semantics and error classes.

  • Embedded in Python and Rust

    Run in process with no server. Results are Arrow tables, with zero-copy hand-off to pandas, Polars and PyArrow where Arrow allows.

  • See what ran

    EXPLAIN ANALYZE reports rows, time, peak memory and spill bytes for every operator.

Where it is going

  1. Available

    Embedded SQL and DataFrames (Python, Rust)

    Available in 0.2.0

  2. Preview

    Single-node Spark Connect server, so stock PySpark connects unchanged

    In progress

  3. Preview

    Parquet, Iceberg and Delta tables

    In progress

  4. Coming soon

    Streaming with the same SQL as batch

    Planned

  5. Coming soon

    Incrementally maintained materialized views

    Planned

  6. Coming soon

    Distributed execution

    Planned

The public roadmap is on GitHub. Nothing in this table is a date.

Compatibility

Krishiv follows Spark's behaviour where you can observe it, keyed by Spark version, and checks it against Spark's own test results. Where it differs, the difference is listed in the compatibility page. "Spark-compatible" describes that goal and the API shape. Krishiv is not Apache Spark, and Apache Spark is a trademark of the Apache Software Foundation.

Quickstart

pip install "krishiv[pyarrow]"
import tempfile
from pathlib import Path

import pyarrow as pa
import pyarrow.parquet as pq

import krishiv
from krishiv.sql import functions as F

spark = krishiv.session()  # a PySpark-style SparkSession, in process

spark.sql("SELECT 1 AS answer").show()

path = str(Path(tempfile.mkdtemp()) / "orders.parquet")
pq.write_table(
    pa.table(
        {
            "region": ["east", "west", "east", "north", "west"],
            "amount": [10.0, 20.0, 5.5, 7.25, 30.0],
        }
    ),
    path,
)
orders = spark.read.parquet(path)
orders.createOrReplaceTempView("orders")

by_region = (
    orders.filter(F.col("amount") > 6)
    .groupBy("region")
    .agg(F.sum("amount").alias("revenue"))
    .orderBy("region")
)
by_region.show()
print(by_region.toArrow())  # a pyarrow.Table; also pa.table(by_region), polars.DataFrame(by_region)

same = spark.sql("SELECT region, sum(amount) AS revenue FROM orders WHERE amount > 6 GROUP BY region ORDER BY region")
assert same.collect() == by_region.collect()

Measured numbers

Method. Standard TPC-H, TPC-DS and ClickBench query sets over Parquet, read directly with no pre-loading step. Each query runs after warm-up iterations; we report the median of the timed iterations with its spread, the commit it was measured on, the machine, thread count and memory limit. Numbers are published only from a clean, committed tree, and the harness is in the repository under bench/ so you can run it yourself.

[Benchmark chart: TPC-H SF10, SF100, SF1000, with method; numbers at launch]