| <!--- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| |
| (distributing_work)= |
| |
| # Distributing work |
| |
| A single {py:class}`~datafusion.SessionContext` already uses every |
| core on the machine — DataFusion partitions and parallelizes within |
| a process without being asked. See |
| {doc}`../configuration` for tuning that. |
| |
| This section is about the step after that: getting work onto more |
| than one process or more than one machine. There are two roads, and |
| they suit different problems. |
| |
| ## Pick your road |
| |
| **You decide the partitioning → ship expressions.** |
| |
| You already know how the data divides — one file per worker, one |
| customer per worker, one parameter setting per worker. You build an |
| {py:class}`~datafusion.Expr` in the driver and hand a copy to each |
| worker along with its slice. Standard Python `pickle` moves it, so |
| {py:mod}`multiprocessing`, Ray, and anything else that ships function |
| arguments works with no extra machinery. |
| |
| Best for embarrassingly-parallel work: parameter sweeps, per-file |
| transforms, scoring batches. Available today. |
| |
| → {ref}`distributed_expressions` |
| |
| **A library decides the partitioning → install a query engine.** |
| |
| You write one ordinary SQL or DataFrame query against a table too |
| large for one machine, and an engine library splits the plan into |
| stages, runs them on its workers, and reassembles the result. You do |
| not partition anything and your queries do not change. |
| |
| Best for large-scale analytical queries — joins and aggregations over |
| data that does not fit on one node. Being built upstream; not yet |
| usable from datafusion-python. |
| |
| → {ref}`distributed_query_engines` |
| |
| ## Choosing between them |
| |
| The two are not competing implementations of one feature. The |
| question is who owns the partitioning decision. |
| |
| If you can state the partitioning in one line — "one worker per input |
| file" — the expression road is simpler, has no cluster to operate, |
| and works now. If stating it requires knowing how a join will |
| shuffle, that decision belongs to a query planner, which is what an |
| engine library provides. |
| |
| They also compose. An engine handles the query; expressions handle |
| whatever you want to fan out around it. |
| |
| ```{toctree} |
| :maxdepth: 2 |
| |
| expressions |
| query-engines |
| ``` |