Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 2.3k
Implement hash partitioned aggregation#320
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
c90bfc93dc2cf4381df9c9dd926f268eb1e358b21b6824f1b207dbf46ea59c1a0db9ededf9396f25800896b5a966c9093be13e3458f4522d48c8b932fc12ebFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -636,6 +636,9 @@ pub struct ExecutionConfig { | ||
| /// Should DataFusion repartition data using the join keys to execute joins in parallel | ||
| /// using the provided `concurrency` level | ||
| pub repartition_joins: bool, | ||
| /// Should DataFusion repartition data using the aggregate keys to execute aggregates in parallel | ||
| /// using the provided `concurrency` level | ||
| pub repartition_aggregations: bool, | ||
| } | ||
| impl ExecutionConfig { | ||
| @@ -663,6 +666,7 @@ impl ExecutionConfig { | ||
| create_default_catalog_and_schema: true, | ||
| information_schema: false, | ||
| repartition_joins: true, | ||
| repartition_aggregations: true, | ||
| } | ||
| } | ||
| @@ -746,6 +750,11 @@ impl ExecutionConfig { | ||
| self.repartition_joins = enabled; | ||
| self | ||
| } | ||
| /// Enables or disables the use of repartitioning for aggregations to improve parallelism | ||
| pub fn with_repartition_aggregations(mut self, enabled: bool) -> Self { | ||
| self.repartition_aggregations = enabled; | ||
| self | ||
| } | ||
| } | ||
| /// Holds per-execution properties and data (such as starting timestamps, etc). | ||
| @@ -1351,7 +1360,6 @@ mod tests { | ||
| #[tokio::test] | ||
| async fn aggregate_grouped() -> Result<()> { | ||
| let results = execute("SELECT c1, SUM(c2) FROM test GROUP BY c1", 4).await?; | ||
| assert_eq!(results.len(), 1); | ||
Dandandan marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| let expected = vec![ | ||
| "+----+---------+", | ||
| @@ -1371,7 +1379,6 @@ mod tests { | ||
| #[tokio::test] | ||
| async fn aggregate_grouped_avg() -> Result<()> { | ||
| let results = execute("SELECT c1, AVG(c2) FROM test GROUP BY c1", 4).await?; | ||
| assert_eq!(results.len(), 1); | ||
| let expected = vec![ | ||
| "+----+---------+", | ||
| @@ -1392,7 +1399,6 @@ mod tests { | ||
| async fn boolean_literal() -> Result<()> { | ||
| let results = | ||
| execute("SELECT c1, c3 FROM test WHERE c1 > 2 AND c3 = true", 4).await?; | ||
| assert_eq!(results.len(), 1); | ||
| let expected = vec![ | ||
| "+----+------+", | ||
| @@ -1414,7 +1420,6 @@ mod tests { | ||
| async fn aggregate_grouped_empty() -> Result<()> { | ||
| let results = | ||
| execute("SELECT c1, AVG(c2) FROM test WHERE c1 = 123 GROUP BY c1", 4).await?; | ||
| assert_eq!(results.len(), 1); | ||
| let expected = vec!["++", "||", "++", "++"]; | ||
| assert_batches_sorted_eq!(expected, &results); | ||
| @@ -1425,7 +1430,6 @@ mod tests { | ||
| #[tokio::test] | ||
| async fn aggregate_grouped_max() -> Result<()> { | ||
| let results = execute("SELECT c1, MAX(c2) FROM test GROUP BY c1", 4).await?; | ||
| assert_eq!(results.len(), 1); | ||
| let expected = vec![ | ||
| "+----+---------+", | ||
| @@ -1445,7 +1449,6 @@ mod tests { | ||
| #[tokio::test] | ||
| async fn aggregate_grouped_min() -> Result<()> { | ||
| let results = execute("SELECT c1, MIN(c2) FROM test GROUP BY c1", 4).await?; | ||
| assert_eq!(results.len(), 1); | ||
| let expected = vec![ | ||
| "+----+---------+", | ||
| @@ -1629,7 +1632,6 @@ mod tests { | ||
| #[tokio::test] | ||
| async fn count_aggregated() -> Result<()> { | ||
| let results = execute("SELECT c1, COUNT(c2) FROM test GROUP BY c1", 4).await?; | ||
| assert_eq!(results.len(), 1); | ||
| let expected = vec![ | ||
| "+----+-----------+", | ||
| @@ -1681,7 +1683,6 @@ mod tests { | ||
| &mut ctx, | ||
| "SELECT date_trunc('week', t1) as week, SUM(c2) FROM test GROUP BY date_trunc('week', t1)", | ||
| ).await?; | ||
| assert_eq!(results.len(), 1); | ||
| let expected = vec![ | ||
| "+---------------------+---------+", | ||
| @@ -1925,7 +1926,6 @@ mod tests { | ||
| ]; | ||
| let results = run_count_distinct_integers_aggregated_scenario(partitions).await?; | ||
| assert_eq!(results.len(), 1); | ||
| let expected = vec![ | ||
| "+---------+-----------------+------------------------+-------------------------+-------------------------+-------------------------+-------------------------+--------------------------+--------------------------+--------------------------+", | ||
| @@ -1952,7 +1952,6 @@ mod tests { | ||
| ]; | ||
| let results = run_count_distinct_integers_aggregated_scenario(partitions).await?; | ||
| assert_eq!(results.len(), 1); | ||
| let expected = vec![ | ||
| "+---------+-----------------+------------------------+-------------------------+-------------------------+-------------------------+-------------------------+--------------------------+--------------------------+--------------------------+", | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -78,6 +78,13 @@ pub enum AggregateMode { | ||
| Partial, | ||
| /// Final aggregate that produces a single partition of output | ||
| Final, | ||
| /// Final aggregate that works on pre-partitioned data. | ||
| /// | ||
| /// This requires the invariant that all rows with a particular | ||
| /// grouping key are in the same partitions, such as is the case | ||
| /// with Hash repartitioning on the group keys. If a group key is | ||
| /// duplicated, duplicate groups would be produced | ||
| FinalPartitioned, | ||
| } | ||
| /// Hash aggregate execution plan | ||
| @@ -123,7 +130,7 @@ fn create_schema( | ||
| fields.extend(expr.state_fields()?.iter().cloned()) | ||
| } | ||
| } | ||
| AggregateMode::Final => { | ||
| AggregateMode::Final | AggregateMode::FinalPartitioned => { | ||
| // in final mode, the field with the final result of the accumulator | ||
| for expr in aggr_expr { | ||
| fields.push(expr.field()?) | ||
| @@ -204,6 +211,9 @@ impl ExecutionPlan for HashAggregateExec { | ||
| fn required_child_distribution(&self) -> Distribution { | ||
| match &self.mode { | ||
| AggregateMode::Partial => Distribution::UnspecifiedDistribution, | ||
| AggregateMode::FinalPartitioned => Distribution::HashPartitioned( | ||
| self.group_expr.iter().map(|x| x.0.clone()).collect(), | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 | ||
| ), | ||
| AggregateMode::Final => Distribution::SinglePartition, | ||
| } | ||
| } | ||
| @@ -454,7 +464,7 @@ fn group_aggregate_batch( | ||
| }) | ||
| .try_for_each(|(accumulator, values)| match mode { | ||
| AggregateMode::Partial => accumulator.update_batch(&values), | ||
| AggregateMode::Final => { | ||
| AggregateMode::FinalPartitioned | AggregateMode::Final => { | ||
| // note: the aggregation here is over states, not values, thus the merge | ||
| accumulator.merge_batch(&values) | ||
| } | ||
| @@ -807,7 +817,7 @@ fn aggregate_expressions( | ||
| Ok(aggr_expr.iter().map(|agg| agg.expressions()).collect()) | ||
| } | ||
| // in this mode, we build the merge expressions of the aggregation | ||
| AggregateMode::Final => Ok(aggr_expr | ||
| AggregateMode::Final | AggregateMode::FinalPartitioned => Ok(aggr_expr | ||
| .iter() | ||
| .map(|agg| merge_expressions(agg)) | ||
| .collect::<Result<Vec<_>>>()?), | ||
| @@ -901,7 +911,9 @@ fn aggregate_batch( | ||
| // 1.3 | ||
| match mode { | ||
| AggregateMode::Partial => accum.update_batch(values), | ||
| AggregateMode::Final => accum.merge_batch(values), | ||
| AggregateMode::Final | AggregateMode::FinalPartitioned => { | ||
| accum.merge_batch(values) | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| @@ -1074,7 +1086,7 @@ fn finalize_aggregation( | ||
| .collect::<Result<Vec<_>>>()?; | ||
| Ok(a.iter().flatten().cloned().collect::<Vec<_>>()) | ||
| } | ||
| AggregateMode::Final => { | ||
| AggregateMode::Final | AggregateMode::FinalPartitioned => { | ||
| // merge the state to the final value | ||
| accumulators | ||
| .iter() | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.