[!NOTE] Automatische vertaling Dit artikel is automatisch vertaald vanuit de oorspronkelijke Engelse versie.

Jarenlang heeft Pandas de tabulaire verwerking in geheugen gedaan, terwijl Apache Spark verantwoordelijk was voor de gedistribueerde variant. Deze opdeling werkte goed zolang de gegevens gestructureerd waren.

Moderne pipelines-systemen verwerken ook afbeeldingen, audio en video. In dergelijke werklasten kan de CPU-decoding leiden tot een vertraging van de GPU inference-processen, terwijl de garbage collection van de JVM en het Global Interpreter Lock in Python de throughput-prestaties beperken. Nieuwe engines maken gebruik van Rust en Apache Arrow om deze kosten te verminderen.

Om de opties met elkaar te vergelijken, heb ik Polars, DataFusion, Daft, Ray Data en Spark getest op twee echte datasets. Taxiriten in NYC vormen tabulaire data; de Food-101-foto’s vertegenwoordigen een multimodale pipeline.

De repository engine-comparison-demo bevat de code. Voer deze uit op uw eigen hardware, aangezien de prestaties van de engine afhankelijk zijn van de machine, dataset, en de werklast.

TL;DR: Begin met het specificeren van de vorm van het werkproces, in plaats van te streven naar een benchmark winnaar. Polars is een sterke standaardoptie voor lokale DataFrame pipelines; DataFusion is geschikt voor teams embedding die een query-engine nodig hebben; Ray Data en Daft zijn ontworpen voor gemengde CPU/GPU pipelines omgevingen; en Spark blijft een betrouwbare keuze voor distribueerde SQL-werkzaamheden en ETL-processen. De gepubliceerde versnellingen in deze gids zijn specifiek gebaseerd op bepaalde werklasten en vormen geen algemeen geldende garanties. Voer de bijbehorende benchmarks opnieuw uit op uw eigen gegevens en hardware voordat u een keuze maakt.


Typen dataverwerkingswerklasten

AI-agents zijn gespecialiseerd, dus de eerste vraag die beantwoord moet worden, is wat voor soort werklast u eigenlijk heeft. De grootste indeling is tussen gestructureerde en multimodale werklasten.

Twee werelden van data: gestructureerd versus multimodaal

Gestructureerde of tabulaire gegevens omvatten filtering, aggregatie en joins. Ze zijn meestal gebonden aan CPU en passen vaak in het geheugen. Volgens Polars is dat ongeveer 90% van de queries verwerkt minder dan 1 TB., Zo kunnen er veel meer agenten op één moderne machine draaien in plaats van op een cluster.

Multimodale AI systemen verwerken afbeeldingen, audio of video. Inference kan worden uitgevoerd op een GPU tijdens het CPU decoderen, terwijl beperkingen met betrekking tot externe lezingen en batchverwerking de pipeline beïnvloeden. Het verhoudingsgetal varieert afhankelijk van de instellingen en operators; daarom dient de benutting over de hele werkwijze te worden gemeten in plaats van de GPU apart in te schatten.

De nieuwere engines richten zich op verschillende aspecten van dit vakgebied. Natieve uitvoering kan de overhead van Python verminderen, Arrow-compatibele interfaces kunnen de kosten voor gegevensuitwisseling verlagen, en streamuitvoering kan het geheugenverbruik beperken bij datasets systemen die groter zijn dan RAM. Geen van deze voordelen is automatisch van toepassing op elke operator of conversie.


Deel 1: verwerking op één node

Pandas geeft de voorkeur aan een eager, in-memory programmeerstijl model. Veel veelgebruikte operaties genereren tussentijdse resultaten, en parallelle uitvoering wordt niet gecoördineerd door een query-optimalisator. Deze afweging zorgt ervoor dat exploratieve code eenvoudig te schrijven blijft, maar kan duur worden bij grotere analytische scans. Bij Polars’s PDS-H benchmark Bij een schaalfactor van 10 duurde de verwerking met Pandas ongeveer 365 seconden voor het gehele pakket, terwijl de streamengine van Polars slechts 3,89 seconden nodig had. Dit resultaat van ongeveer 94x geeft weer hoe benchmark en de configuratie van invloed zijn; het is geen algemene omrekeningsfactor van Pandas naar Polars.

Eager uitvoering versus Lazy uitvoering

Polars voor lokale tabulaire gegevens pipelines

Polars Dit vormt een praktische standaardoptie wanneer een lokale DataFrame pipeline te groot is geworden voor een eenvoudige, enkelprocesuele uitvoering. De ‘lazy’ API-aanpak maakt eerst een queryplan op voordat de uitvoering begint, waardoor optimalisaties zoals predicate pushdown en projection pruning mogelijk worden. Vervolgens kan de engine operators parallel uitvoeren en, waar dat mogelijk is, in stroomvormige batches.

Naarmate de hoeveelheid gegevens toeneemt, wordt de kloof groter. Bij Schaalfactor 100 (~100 GB), De streamingengine van Polars voltooide de verwerking in 23,94 seconden, vergeleken met 152,27 seconden voor diens eigen in-memoryengine – dat is ongeveer 6 keer sneller, zelfs bij gegevens die groter zijn dan het RAM-geheugen.

Van engine_comparison_examples.ipynb:

import polars as pl

# scan_parquet reads only the schema — no data loaded yet
q = (
    pl.scan_parquet("yellow_tripdata_2024-01.parquet")
    .filter(
        (pl.col("trip_distance") > 5.0)
        & (pl.col("total_amount") > 30.0)
    )
    .group_by("payment_type")
    .agg(
        pl.col("total_amount").mean().alias("avg_fare"),
        pl.col("trip_distance").mean().alias("avg_distance"),
        pl.len().alias("trip_count"),
    )
)

# The entire plan is optimized and executed here, in parallel
result = q.collect()

Het belangrijkste verschil ligt in de uitvoering model. Bij de bovenstaande ‘lazy query’ kan Polars de filtering en kolomselectie doorgeven aan de Parquet-scanning. Hierdoor kunnen rijgroepen worden overgeslagen en ongebruikte kolommen worden vermeden. Een typische ‘eager Pandas pipeline’ beschikt niet over een geoptimaliseerd plan voor de hele query, hoewel zorgvuldig gebruik van Parquet-filters, geselecteerde kolommen en alternatieve backends-methoden een deel van dit nadeel kunnen wegnemen.

DataFusion voor ingebouwde query-engineën

Waar Polars een bibliotheek is die je rechtstreeks gebruikt, DataFusion het is de engine waarop andere engines worden gebouwd. Het zorgt voor de stroomvoorziening InfluxDB 3.0, GreptimeDB, en die van Apple Comet Spark-versneller.

In november 2024 De ClickBench-run die is gepubliceerd door het DataFusion-project, DataFusion was verantwoordelijk voor de geteste Parquet-configuraties op één node. Het Embucket-team publiceerde later een TPC-H schaalfactor-1000 uitvoering op één grote node. Deze resultaten tonen wat een schaalvergroting onder specifieke omstandigheden kan opleveren; ze bewijzen niet dat elke 1 TB werklast een cluster moet worden vermeden.

Van engine_comparison_examples.ipynb:

from datafusion import SessionContext

ctx = SessionContext()
ctx.register_parquet("taxi", "yellow_tripdata_2024-01.parquet")

# SQL executed directly against Parquet — no intermediate copies
df = ctx.sql("""
    SELECT payment_type,
           COUNT(*)           AS trip_count,
           AVG(trip_distance) AS avg_distance,
           AVG(total_amount)  AS avg_fare
    FROM taxi
    WHERE trip_distance > 5.0 AND total_amount > 30.0
    GROUP BY payment_type
    ORDER BY trip_count DESC
""")
result = df.to_pandas()

De sterke kant van DataFusion is zijn modulariteit. De extensie APIs omvat geavanceerde catalogi, provider voor tabellen, regels voor optimalisatie en uitvoerplannen. Daarom wordt deze gebruikt wanneer iemand een aangepaste dataplatform of embedding een query-engine ontwikkelt voor zijn eigen product.

Onbruikbaar voor multimodale gegevens

Onzinnig Het maakt afbeeldingen, audio, video en embeddings onderdeel van de DataFrame workflow. Het biedt geïntegreerde expressies voor operaties zoals afbeeldingsdecoding en het downloaden van bestanden via URL’s, zodat standaard voorverwerkingsstappen geen iteratie per rij in Python vereisen. Deze integratie is de belangrijkste reden om dit systeem te kiezen boven een algemene tabulaire engine.

Van engine_comparison_examples.ipynb:

import daft

df = daft.read_parquet("yellow_tripdata_2024-01.parquet")

result = (
    df.where(
        (daft.col("trip_distance") > 5.0)
        & (daft.col("total_amount") > 30.0)
    )
    .groupby("payment_type")
    .agg(
        daft.col("total_amount").mean().alias("avg_fare"),
        daft.col("trip_distance").mean().alias("avg_distance"),
        daft.col("trip_distance").count().alias("trip_count"),
    )
    .collect()
)

Als u bekend bent met Pandas, zult u zich bij API direct thuis voelen, maar de onderliggende engine is dezelfde Rust + Arrow-stack die ook wordt gebruikt in Polars en DataFusion. Daft komt echt van pas wanneer de “rows” in uw DataFrame bestaan uit afbeeldingen, PDF’s of tensors.

Enkelvoudige node benchmark

Ik heb alle vier de engines uitgevoerd, evenals de native Rust-versie via Polars-rs, op ongeveer 41 miljoen. NYC-gele taxiritten voor het hele jaar 2024. De volledige resultaten staan in de demo-repo:

Benchmark Resultaten: Prestaties op één node

Bij deze omvang (ongeveer 660 MB in Parquet-formaat) voltooien alle vier de nieuwere engines het proces snel. Het cijfer van 94 keer sneller van Polars naar Pandas dat hierboven wordt weergegeven, is afkomstig uit PDS-H; mijn werklast met 41 miljoen rijen voor taxidata leverde een kleinere verschillen op. Polars, DataFusion, Daft en Polars-rs vielen allemaal binnen hetzelfde ruime bereik, waarbij DataFusion de kortste totale verwerkingstijd noteerde in deze test. Dit is een nuttig resultaat voor deze specifieke query, maar geen stabiele rangschikking: API passendheid en herhaalde metingen op representatieve gegevens moeten uiteindelijk beslissen tussen engines die zo dicht bij elkaar liggen.


Deel 2: multimodale gegevens

Tabulaire ETL-procedures verkleinen doorgaans de hoeveelheid gegevens: er worden filters toegepast, gegevens worden gegroepeerd en er wordt minder opgeslagen dan er wordt gelezen. Multimodale AI pipelines-processen doen het tegenovergestelde. Eén documentpad kan zich ontwikkelen tot tientallen tekst chunks- en embedding-vectoren.

Binnen een conventionele PySpark pipeline worden afbeeldingen en audio vaak als binaire gegevens ingevoerd en verwerkt in Python-bibliotheken voor decodering of transformatie. Het oversteken van de grens tussen de JVM en Python, evenals het serialiseren van de resultaten, kan een aanzienlijk deel van de totale verwerkingstijd innemen. Spark maakt gebruik van Arrow-gebaseerde paden, gevectoriseerde UDF’s en integraties met accelerators, maar deze keuzes vereisen een bewuste ontwerpproces en nauwkeurige meting.

Pipelined uitvoering en GPU-gebruik

Spark plandt werkzaamheden in fasen die worden gescheiden door shuffle-grenzen. Een eenvoudige implementatie kan het downloaden, decode, en inference in een bepaalde volgorde uitvoeren, waardoor er nog steeds capaciteit overblijft voor CPU of GPU. Spark ondersteunt GPU-gebaseerd resourceplanning en plugins, zodat idle-tijd geen onvermijdelijk gevolg is; het belangrijkste is dat overlapping en backpressure geen automatische eigenschappen zijn van een gewone PySpark DataFrame-opdracht.

Pijpleiding van uitvoering Model

Gepipeerde uitvoering is de alternatieve aanpak. In plaats van de verschillende stappen achter elkaar uit te voeren, overlapt de engine de I/O-activiteiten, CPU en GPU inference, zodat op elk moment alleen het langzame onderdeel in afwachting is.

Afbeeldingsverwerking benchmark

Ik heb de prestaties van het beeldverwerkingssysteem getest op 500 echte fotografieën uit de Algemene kennis over voedsel dataset. Resultaten uit de demo-repo:

Benchmark Resultaten: Multimodale prestaties

Polars en DataFusion ontbreken omdat deze test zich richt op native afbeeldingsoperaties in plaats van tabulaire expressies. Tijdens dit testrun met 500 afbeeldingen was de prestatie van Daft’s afbeeldingsroute 3,6 keer sneller dan de referentiestandaard van Pandas + Pillow, terwijl de Rust-implementatie 4,2 keer sneller was. Het voorbeeld is nuttig om de overhead van orchestration zichtbaar te maken, maar het is te klein om op zichzelf al prognoses te kunnen doen over de prestaties in productieomgevingen throughput.


Deel 3: gedistribueerde verwerking

Zodra één enkele machine niet meer voldoende is, moet je beslissen hoe de werklast wordt verdeeld. Hier beginnen de architectonische verschillen tussen de verschillende agents echt van belang te worden.

Apache Spark

Spark vormt een geavanceerde optie voor grootschalige tabulaire ETL-processen, joins die veel shuffling vereisen, en voor organisaties die al gebruikmaken van zijn ecosysteem. Zijn herstelmechanismen gebaseerd op lineage en de brede platformondersteuning zijn belangrijk wanneer betrouwbaarheid en operationele vertrouwdheid belangrijker zijn dan lokale snelheid. Gemengde CPU/GPU pipelines-scenario’s vereisen een zorgvuldigere configuratie van resources en pipeline-ontwerp dan de SQL-route, waar Ray Data en Daft een meer gerichte abstractie bieden.

Van distributed_spark.ipynb:

from pyspark.sql import SparkSession
from pyspark.sql import functions as F

spark = SparkSession.builder \
    .appName("TaxiETL") \
    .config("spark.sql.adaptive.enabled", "true") \
    .getOrCreate()

orders = spark.read.parquet("s3a://lake/taxi/*.parquet")
zones = spark.read.csv("s3a://lake/taxi_zones.csv", header=True)

# Spark excels at this: joining massive tables with a shuffle
result = (
    orders
    .filter(F.col("trip_distance") > 5.0)
    .join(zones, orders.PULocationID == zones.LocationID, "inner")
    .groupBy("Borough")
    .agg(
        F.sum("total_amount").alias("total_revenue"),
        F.avg("total_amount").alias("avg_fare"),
    )
    .orderBy(F.desc("total_revenue"))
)

Ray Data voor heterogene verwerking

Ray Data is ontworpen rondom AI-werklasten. In plaats van de stage-barrières van Spark maakt het gebruik van een streaming model Dit zorgt ervoor dat GPUs gevoed blijft. De functie die de mogelijkheid hiervoor biedt, heet gemengde resourcenscheduling: je kunt aangeven dat één actor “1 GPU, 4 CPUs” wil, terwijl een andere actor alleen CPUs nodig heeft, en Ray regelt de rest.

Amazon heeft verslag uitgebracht meer dan 120 miljoen dollar aan jaarlijkse besparingen Na het verplaatsen van geselecteerde interne dataverwerkingswerloadsen van Spark naar Ray, geeft het rapport aan dat de kostenprestaties in het proof of concept met 91% verbeterd zijn en in de productieomgeving met 82% per GiB S3-invoer. De schaal is opmerkelijk, maar dit is een migratiecasestudy voor specifieke workloadsen en niet een verwachte besparing bij een typische implementatie van Ray.

Van distributed_ray.ipynb:

import ray

ray.init()

ds = ray.data.read_images("s3://my-bucket/food101/")

class ImageClassifier:
    def __init__(self):
        import torch
        from torchvision.models import resnet18, ResNet18_Weights
        self.model = resnet18(weights=ResNet18_Weights.DEFAULT).cuda()
        self.model.eval()
        self.preprocess = ResNet18_Weights.DEFAULT.transforms()

    def __call__(self, batch):
        import torch
        tensors = torch.stack([
            self.preprocess(img) for img in batch["image"]
        ]).cuda()
        with torch.no_grad():
            preds = self.model(tensors)
        return {
            "prediction": preds.argmax(dim=1).cpu().numpy(),
            "confidence": preds.max(dim=1).values.cpu().numpy(),
        }

# ActorPoolStrategy creates persistent GPU workers
predictions = ds.map_batches(
    ImageClassifier,
    compute=ray.data.ActorPoolStrategy(size=4),
    num_gpus=1,
    batch_size=64,
)
predictions.write_parquet("s3://output/predictions/")

Een detail dat het waard is om te weten: naarmate u meer CPUs toevoegt per GPU, schaalt Ray Data mee, terwijl andere engines op hun niveau blijven steken. In Anyscale’s benchmarks, Het overstappen van een verhouding van 4:1 naar 32:1 CPU-naar-GPU leverde een drievoudige versnelling op bij de verwerking van afbeeldingen inference, omdat de CPU feeders eindelijk gelijk konden oplopen met de GPU.

Gedeeld Daft

Daft schaalbaarheid behaalt door zijn Flotilla-motor: Eén Swordfish-worker per node, waarbij Flotilla op een hoger niveau verantwoordelijk is voor het plannen op clusterniveau. Swordfish zorgt voor de lokale uitvoering in Rust en voor pipelines I/O via streamverwerking in kleine batches, zodat elke node continu bezig blijft zonder te hoeven wachten op de volgende stap.

In benchmarks gepubliceerd door Daft, Flotilla werkte 2–18 keer sneller dan de geteste Spark-implementaties bij vier multimodale werklasten. De grootste verschillen werden waargenomen in het geval van video-objectdetectie. Beschouw dit resultaat als bewijs dat de uitvoeringsontwerp een belangrijke factor is voor deze pipelines, en vergelijk het vervolgens met de resultaten van Anyscale en met een lokale test.

Anyscale, het bedrijf achter Ray, heeft gepubliceerd een concurrerende benchmark waarin Ray Data na het tunen de kloof op instellingen met hoge CPU waarden heeft verkleind of zelfs weggenomen. Samen vormen deze twee onderzoeken van leveranciers een reden om representatieve operators en de CPU-tot-GPU verhoudingen te testen, in plaats van een definitieve ranglijst te trekken.

Van distributed_daft.ipynb:

import daft
from daft import col

# Daft's Flotilla engine distributes work across the cluster
df = daft.read_parquet("s3://data-lake/pdf_metadata/*.parquet")

# Download PDFs — Daft parallelizes downloads in Rust
df = df.with_column("pdf_bytes", col("pdf_url").url.download())

# Define a GPU UDF for embedding generation
@daft.udf(return_dtype=daft.DataType.list(daft.DataType.float32()))
class TextEmbedder:
    def __init__(self):
        from sentence_transformers import SentenceTransformer
        self.model = SentenceTransformer("all-MiniLM-L6-v2", device="cuda")

    def __call__(self, text_col):
        texts = text_col.to_pylist()
        embeddings = self.model.encode(texts, batch_size=32)
        return [emb.tolist() for emb in embeddings]

# Daft schedules CPU downloads and GPU embeddings simultaneously
df = df.with_column("embedding", TextEmbedder(col("text")))
df.write_parquet("s3://output/embeddings/")

Gedeeld vergelijken

FunctieSparkRay Data
Uitvoering ModelTaak-per-core, gebaseerd op partitieënStreamingtaken en actorenZwaardvis-per-node, stromende batches
SterktepuntenGrote schaal SQL/ETL, fouttolerantieHeterogene rekenkracht en GPU-verzadigingMultimodale pijpliningen met beperkte geheugengebruik
GPU controlesResourceplanning in combinatie met ecosystemplug-insExpliciete taak- en actorbronnenGeïntegreerde CPU/GPU pipeline-scheduling
Typische afstellingExecutors, geheugen, partities, versnellersBatchverwerking, actoren, objectopslagBatchverwerking, resources, paralleliteit van I/O
Goed evaluatiegevalGrote SQL/ETL-opdrachten en taken met veel shufflingTraining of inference met gemengde bronnenMultimodale invoer en transformatie

Deel 4: de rol van Rust en Arrow

Onder het perspectief van de concurrentie is de convergentie het interessantere verhaal. Polars, Daft en DataFusion maken intensief gebruik van Rust, terwijl Ray naast zijn Python-componenten ook geïntegreerde onderdelen bevat APIs. Ze kunnen allemaal gegevens uitwisselen via bepaalde delen van Apache Arrow ecosysteem.

Rust en Arrow-convergentie

De Arrow PyCapsule-interface (__arrow_c_stream__ Het protocol biedt compatibele bibliotheken een standaardmethode om Arrow-stromen uit te wisselen. Door overdracht kan worden vermeden dat gegevens rij voor rij worden geserialiseerd, en buffers kunnen worden hergebruikt wanneer de schema’s en geheugenindelingen overeenkomen. Materialisatie, herverdeling van data, typeconversie of overdracht naar hardware kan desondanks nog steeds kopieën van de gegevens vereisen; controleer daarom de overdracht via profiling in plaats van ervan uit te gaan dat deze kosteloos verloopt.

from datafusion import SessionContext
import polars as pl

# Compute in DataFusion (Rust-native execution)
ctx = SessionContext()
ctx.register_parquet("events", "events.parquet")
df = ctx.sql("""
    SELECT user_id, COUNT(*) as event_count
    FROM events WHERE event_type = 'purchase'
    GROUP BY user_id HAVING COUNT(*) > 5
""")

# Convert through Arrow; compatible buffers may be reused
arrow_table = df.to_arrow_table()
df_polars = pl.from_arrow(arrow_table)

# Continue analysis in Polars
result = df_polars.with_columns(
    pl.col("event_count").rank().alias("rank")
).sort("rank")

Waarom maken deze nieuwere engines gebruik van Rust voor de native uitvoering?

  1. Geen tracing garbage collector in Rust-code. Eigendomshierarchieën geven de native operators meer directe controle over toewijzing en vrijgave van geheugen. Dit kan latency gerelateerde problemen verminderen, maar het voorkomt geen geheugenpressie of fouten door gebrek aan beschikbaar geheugen.

  2. Compacte, native representaties. Rust-structuren bevatten geen Java-objectheaders. Het praktische voordeel hangt af van de lay-out van de engine: kolommatige JVM-systemen vermijden eveneens om elke waarde als een apart object weer te geven.

  3. Sterkere controles op gelijktijdige uitvoering. Safe Rust sluit veel data races al tijdens de compilatie uit. De enginecode kan nog steeds onveilige blokken en logische fouten met betrekking tot gelijktijdige uitvoering bevatten, maar de taal beperkt het aantal mogelijke foutpunten aanzienlijk.

In combinatie met Arrow’s kolommatige geheugenopbouw kunnen deze keuzes de overhead van toewijzing en serialisatie verminderen. Ze verwijderen deze overhead echter niet bij elke grens; Python-objecten, netwerktransport, oncompatibele schema’s en het verplaatsen van apparaten spelen nog steeds een rol.


Deel 5: het gebruiken van meerdere engines

Je hoeft de hele platform niet via één enkele engine te laten draaien. Compositie is nuttig wanneer het opzetten hiervan goedkoper is dan het laten verwerken van elke werklast door één systeem.

De co-existentie Model: meermotorige Pipeline

Een mogelijke relay maakt gebruik van Spark voor de standaard lakehouse-joins, schrijft de resultaten op in een open tabel- of bestandsformaat, en geeft deze door aan Ray Data of Daft voor GPU inference of multimodale transformaties. Polars of DuckDB kunnen worden ingezet voor lokale analyse van dezelfde bestanden. Een kleinere team kan mogelijk alleen één van deze engines nodig hebben; voeg er een extra bij wanneer een gemeten bottleneck de operationele vereisten rechtvaardigt.

Wat deze samenstelling mogelijk maakt, zijn open formaten: Parquet, Delta, Iceberg en Arrow. Elke engine in de stack leest en schrijft deze formaten op natieve manier, zodat de overdracht tussen verschillende stappen slechts een bestandsnaam vereist.

Selectie van de engine op basis van het evaluatiegeval

EvaluatiecasusLijst van kandidatenValideren
Lokale analytische DataFramesPolars / DuckDBAPI combinatie van fit, geheugen en query’s
Bestaande gedistribueerde SQL/ETL-oplossingenApache SparkGedrag bij shuffelen, uitvoeringsoperaties, kosten
Python-gebonden parallelle verwerkingDask / RayOverhead van de scheduler, fout model
Gemengde CPU/GPU-training of inferenceRay Data / DaftAcceleratorenbenutting, terugschakeling
Multimodale invoerDaft / Ray DataNatuurlijke operators, gedrag bij herproberen
Geïntegreerde query-engineDataFusionExtensie APIs, SQL-dekking

Diagonaal schalen

Lang was de keuze beperkt tot scale up (een grotere machine) of scale out (meer machines). Polars Cloud Er wordt op dit moment iets dergelijks gedaan, wat men diagonale schaling noemt: er wordt horizontaal geschaald terwijl gegevens uit de cloudopslag worden gelezen om de I/O-capaciteit optimaal te benutten, waarna het systeem samenvalt tot één grote node zodra filters en aggregaties de hoeveelheid gegevens hebben verminderd, waardoor een gedistribueerde shuffeling volledig wordt vermeden.

De belangrijkste les is om de kosten per succesvolle taak te vergelijken, en niet de prijs per uur voor een instans. Een grotere node kan goedkoper zijn wanneer de besparing door runtime groter is dan de hogere kosten, maar het eindresultaat hangt af van de I/O-belasting, de geheugendruk en de hoeveelheid werk die al wordt uitgevoerd voordat er een shuffle plaatsvindt.


De vergelijking reproduceren

De demo-repository voor de companion Het bevat de scripts, notebooks en omgeving die worden gebruikt voor de vergelijkingen. Het volgende snelle commando maakt gebruik van een maand aan taxidata; volg de instructies van het repository voor dataset om de grotere, jaarlange analyse die eerder is getoond opnieuw te genereren.

# Install dependencies
uv sync

# Run the tabular benchmark (~2.9M NYC taxi trips)
uv run python -m engine_comparison.benchmarks.tabular

# Run the multimodal benchmark (500 real food photos)
uv run python -m engine_comparison.benchmarks.multimodal

# Run native Rust benchmarks (Polars-rs + image crate)
cd rust_benchmark && cargo run --release && cd ..

In het repository zijn ook notebooks te vinden voor naast elkaar geplaatste API vergelijkingen, evenals Docker Compose-configuraties voor lokale, gedistribueerde uitvoeringen van Spark, Ray en Daft.


Belangrijkste conclusies

  1. Bewijs dat één machine onvoldoende is. Uit schaalvergrotingsexperimenten blijkt dat sommige grote analytische scans op één enkele node passen. Meet de vereisten met betrekking tot geheugen, I/O, data‑spill en herstel voordat je de extra overhead van een cluster overweegt.

  2. Uitvoering models is belangrijker dan bekende syntaxis. Lazige planning-, pushdown-, stream- en parallelle operators verklaren een groot deel van het verschil tussen een eager DataFrame-script en een analytische engine.

  3. Meet de gehele accelerator pipeline. Decode, netwerk-I/O, batchverwerking, serialisatie en backpressure bepalen of een GPU continu bezig blijft. Ray Data en Daft maken deze overlappende aspecten tot een centrale abstractie; Spark kan dit ondersteunen door middel van extra ontwerpkenmerken en hulpmiddelen.

  4. Kies eerst op basis van de werkbelasting, en vervolgens benchmark. Maak gebruik van de geschiktheid voor het bestaande ecosysteem om het aantal opties te beperken, en kies op basis van een representatief eind-tot-eindwerkproces. De resultaten van de benchmark door leveranciers zijn slechts hypothesen, geen garanties.

  5. Open formaten maken het mogelijk om gemakkelijk van keuze te wisselen. Interfaceën die compatibel zijn met pijlen, Parquet en open tabelformaten kunnen de kosten voor overdracht verminderen. Controleer of een bepaalde conversie buffers hergebruikt of ze kopiëert.

Als u een uitgangspunt nodig heeft, kunt u overwegen om Polars te gebruiken voor lokale tabulaire gegevensverwerking pipeline, en Daft of Ray Data voor gemengde CPU/GPU pipeline situaties. Kies voor Spark wanneer de gedistribueerde uitvoeringsmogelijkheden, het ecosysteem of de bestaande operationele infrastructuur voldoen aan uw vereisten—niet alleen wanneer de dataset een bepaalde grootte overschrijdt.


Referenties

Benchmarks en prestatiegegevens

Motoren en frameworks

Architectuur en ecosysteem

Demo-repository

Datasets