Skip to content

Commit ec173ab

Browse files
alambakurmustafa
andauthored
Refactor into LexOrdering::collapse, LexRequirement::collapse avoid clone (#14038)
* Move collapse_lex_ordering to Lexordering::collapse * reduce diff * avoid clone, cleanup * Introduce LexRequirement::collapse * Improve performance of collapse, from @akurmustafa alamb#26 fix formatting * Revert "Improve performance of collapse, from @akurmustafa" This reverts commit a44acfd. * remove incorrect comment --------- Co-authored-by: Mustafa Akur <[email protected]>
1 parent 918ac1b commit ec173ab

File tree

7 files changed

+62
-48
lines changed

7 files changed

+62
-48
lines changed

datafusion/physical-expr-common/src/sort_expr.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,22 @@ impl LexOrdering {
409409
.map(PhysicalSortExpr::from)
410410
.collect()
411411
}
412+
413+
/// Collapse a `LexOrdering` into a new duplicate-free `LexOrdering` based on expression.
414+
///
415+
/// This function filters duplicate entries that have same physical
416+
/// expression inside, ignoring [`SortOptions`]. For example:
417+
///
418+
/// `vec![a ASC, a DESC]` collapses to `vec![a ASC]`.
419+
pub fn collapse(self) -> Self {
420+
let mut output = LexOrdering::default();
421+
for item in self {
422+
if !output.iter().any(|req| req.expr.eq(&item.expr)) {
423+
output.push(item);
424+
}
425+
}
426+
output
427+
}
412428
}
413429

414430
impl From<Vec<PhysicalSortExpr>> for LexOrdering {
@@ -540,6 +556,21 @@ impl LexRequirement {
540556
.collect(),
541557
)
542558
}
559+
560+
/// Constructs a duplicate-free `LexOrderingReq` by filtering out
561+
/// duplicate entries that have same physical expression inside.
562+
///
563+
/// For example, `vec![a Some(ASC), a Some(DESC)]` collapses to `vec![a
564+
/// Some(ASC)]`.
565+
pub fn collapse(self) -> Self {
566+
let mut output = Vec::<PhysicalSortRequirement>::new();
567+
for item in self {
568+
if !output.iter().any(|req| req.expr.eq(&item.expr)) {
569+
output.push(item);
570+
}
571+
}
572+
LexRequirement::new(output)
573+
}
543574
}
544575

545576
impl From<LexOrdering> for LexRequirement {

datafusion/physical-expr/src/equivalence/class.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
use super::{add_offset_to_expr, collapse_lex_req, ProjectionMapping};
18+
use super::{add_offset_to_expr, ProjectionMapping};
1919
use crate::{
2020
expressions::Column, LexOrdering, LexRequirement, PhysicalExpr, PhysicalExprRef,
2121
PhysicalSortExpr, PhysicalSortRequirement,
@@ -526,12 +526,13 @@ impl EquivalenceGroup {
526526
&self,
527527
sort_reqs: &LexRequirement,
528528
) -> LexRequirement {
529-
collapse_lex_req(LexRequirement::new(
529+
LexRequirement::new(
530530
sort_reqs
531531
.iter()
532532
.map(|sort_req| self.normalize_sort_requirement(sort_req.clone()))
533533
.collect(),
534-
))
534+
)
535+
.collapse()
535536
}
536537

537538
/// Projects `expr` according to the given projection mapping.

datafusion/physical-expr/src/equivalence/mod.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use std::sync::Arc;
1919

2020
use crate::expressions::Column;
21-
use crate::{LexRequirement, PhysicalExpr, PhysicalSortRequirement};
21+
use crate::{LexRequirement, PhysicalExpr};
2222

2323
use datafusion_common::tree_node::{Transformed, TransformedResult, TreeNode};
2424

@@ -41,14 +41,9 @@ pub use properties::{
4141
/// It will also filter out entries that are ordered if the next entry is;
4242
/// for instance, `vec![floor(a) Some(ASC), a Some(ASC)]` will be collapsed to
4343
/// `vec![a Some(ASC)]`.
44+
#[deprecated(since = "45.0.0", note = "Use LexRequirement::collapse")]
4445
pub fn collapse_lex_req(input: LexRequirement) -> LexRequirement {
45-
let mut output = Vec::<PhysicalSortRequirement>::new();
46-
for item in input {
47-
if !output.iter().any(|req| req.expr.eq(&item.expr)) {
48-
output.push(item);
49-
}
50-
}
51-
LexRequirement::new(output)
46+
input.collapse()
5247
}
5348

5449
/// Adds the `offset` value to `Column` indices inside `expr`. This function is
@@ -80,7 +75,9 @@ mod tests {
8075
use arrow::datatypes::{DataType, Field, Schema};
8176
use arrow_schema::{SchemaRef, SortOptions};
8277
use datafusion_common::{plan_datafusion_err, Result};
83-
use datafusion_physical_expr_common::sort_expr::LexOrdering;
78+
use datafusion_physical_expr_common::sort_expr::{
79+
LexOrdering, PhysicalSortRequirement,
80+
};
8481

8582
pub fn output_schema(
8683
mapping: &ProjectionMapping,

datafusion/physical-expr/src/equivalence/ordering.rs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,13 @@ impl OrderingEquivalenceClass {
159159
/// Returns the concatenation of all the orderings. This enables merge
160160
/// operations to preserve all equivalent orderings simultaneously.
161161
pub fn output_ordering(&self) -> Option<LexOrdering> {
162-
let output_ordering = self.orderings.iter().flatten().cloned().collect();
163-
let output_ordering = collapse_lex_ordering(output_ordering);
162+
let output_ordering = self
163+
.orderings
164+
.iter()
165+
.flatten()
166+
.cloned()
167+
.collect::<LexOrdering>()
168+
.collapse();
164169
(!output_ordering.is_empty()).then_some(output_ordering)
165170
}
166171

@@ -221,19 +226,6 @@ impl IntoIterator for OrderingEquivalenceClass {
221226
}
222227
}
223228

224-
/// This function constructs a duplicate-free `LexOrdering` by filtering out
225-
/// duplicate entries that have same physical expression inside. For example,
226-
/// `vec![a ASC, a DESC]` collapses to `vec![a ASC]`.
227-
pub fn collapse_lex_ordering(input: LexOrdering) -> LexOrdering {
228-
let mut output = LexOrdering::default();
229-
for item in input.iter() {
230-
if !output.iter().any(|req| req.expr.eq(&item.expr)) {
231-
output.push(item.clone());
232-
}
233-
}
234-
output
235-
}
236-
237229
/// Trims `orderings[idx]` if some suffix of it overlaps with a prefix of
238230
/// `orderings[pre_idx]`. Returns `true` if there is any overlap, `false` otherwise.
239231
fn resolve_overlap(orderings: &mut [LexOrdering], idx: usize, pre_idx: usize) -> bool {

datafusion/physical-expr/src/equivalence/properties.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@ use std::slice::Iter;
2222
use std::sync::Arc;
2323
use std::{fmt, mem};
2424

25-
use super::ordering::collapse_lex_ordering;
2625
use crate::equivalence::class::{const_exprs_contains, AcrossPartitions};
2726
use crate::equivalence::{
28-
collapse_lex_req, EquivalenceClass, EquivalenceGroup, OrderingEquivalenceClass,
29-
ProjectionMapping,
27+
EquivalenceClass, EquivalenceGroup, OrderingEquivalenceClass, ProjectionMapping,
3028
};
3129
use crate::expressions::{with_new_schema, CastExpr, Column, Literal};
3230
use crate::{
@@ -505,15 +503,12 @@ impl EquivalenceProperties {
505503
);
506504
let constants_normalized = self.eq_group.normalize_exprs(constant_exprs);
507505
// Prune redundant sections in the requirement:
508-
collapse_lex_req(
509-
normalized_sort_reqs
510-
.iter()
511-
.filter(|&order| {
512-
!physical_exprs_contains(&constants_normalized, &order.expr)
513-
})
514-
.cloned()
515-
.collect(),
516-
)
506+
normalized_sort_reqs
507+
.iter()
508+
.filter(|&order| !physical_exprs_contains(&constants_normalized, &order.expr))
509+
.cloned()
510+
.collect::<LexRequirement>()
511+
.collapse()
517512
}
518513

519514
/// Checks whether the given ordering is satisfied by any of the existing
@@ -915,7 +910,7 @@ impl EquivalenceProperties {
915910
// Simplify each ordering by removing redundant sections:
916911
orderings
917912
.chain(projected_orderings)
918-
.map(collapse_lex_ordering)
913+
.map(|lex_ordering| lex_ordering.collapse())
919914
.collect()
920915
}
921916

datafusion/physical-plan/src/aggregates/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,9 @@ use datafusion_execution::TaskContext;
4444
use datafusion_expr::{Accumulator, Aggregate};
4545
use datafusion_physical_expr::aggregate::AggregateFunctionExpr;
4646
use datafusion_physical_expr::{
47-
equivalence::{collapse_lex_req, ProjectionMapping},
48-
expressions::Column,
49-
physical_exprs_contains, EquivalenceProperties, LexOrdering, LexRequirement,
50-
PhysicalExpr, PhysicalSortRequirement,
47+
equivalence::ProjectionMapping, expressions::Column, physical_exprs_contains,
48+
EquivalenceProperties, LexOrdering, LexRequirement, PhysicalExpr,
49+
PhysicalSortRequirement,
5150
};
5251

5352
use itertools::Itertools;
@@ -473,7 +472,7 @@ impl AggregateExec {
473472
&mode,
474473
)?;
475474
new_requirement.inner.extend(req);
476-
new_requirement = collapse_lex_req(new_requirement);
475+
new_requirement = new_requirement.collapse();
477476

478477
// If our aggregation has grouping sets then our base grouping exprs will
479478
// be expanded based on the flags in `group_by.groups` where for each

datafusion/physical-plan/src/windows/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ use datafusion_expr::{
3232
PartitionEvaluator, ReversedUDWF, WindowFrame, WindowFunctionDefinition, WindowUDF,
3333
};
3434
use datafusion_physical_expr::aggregate::{AggregateExprBuilder, AggregateFunctionExpr};
35-
use datafusion_physical_expr::equivalence::collapse_lex_req;
3635
use datafusion_physical_expr::{
3736
reverse_order_bys,
3837
window::{SlidingAggregateWindowExpr, StandardWindowFunctionExpr},
@@ -469,8 +468,8 @@ pub fn get_window_mode(
469468
{
470469
let req = LexRequirement::new(
471470
[partition_by_reqs.inner.clone(), order_by_reqs.inner].concat(),
472-
);
473-
let req = collapse_lex_req(req);
471+
)
472+
.collapse();
474473
if partition_by_eqs.ordering_satisfy_requirement(&req) {
475474
// Window can be run with existing ordering
476475
let mode = if indices.len() == partitionby_exprs.len() {

0 commit comments

Comments
 (0)