MCPcopy Create free account
hub / github.com/apache/datafusion / try_pushdown_sort

Method try_pushdown_sort

datafusion/datasource-parquet/src/source.rs:830–962  ·  view source on GitHub ↗

Try to optimize the scan to produce data in the requested sort order. Inputs: 1. The query's required ordering (`order` parameter) 2. The source's equivalence properties (`eq_properties`) # Returns - `Exact`: the source's natural ordering already satisfies the request. The surrounding `SortExec` can be eliminated provided files within each group are non-overlapping (verified by `FileScanConfig`)

(
        &self,
        order: &[PhysicalSortExpr],
        eq_properties: &EquivalenceProperties,
    )

Source from the content-addressed store, hash-verified

828 /// the request (function-wrapped case), this is always `true`
829 /// because we're flipping the file's natural order.
830 fn try_pushdown_sort(
831 &self,
832 order: &[PhysicalSortExpr],
833 eq_properties: &EquivalenceProperties,
834 ) -> datafusion_common::Result<SortOrderPushdownResult<Arc<dyn FileSource>>> {
835 if order.is_empty() {
836 return Ok(SortOrderPushdownResult::Unsupported);
837 }
838
839 // Check if the natural (non-reversed) ordering already satisfies the request.
840 // Parquet metadata guarantees within-file ordering, so if the ordering matches
841 // we can return Exact. FileScanConfig will verify that files within each group
842 // are non-overlapping before declaring the entire scan as Exact.
843 if eq_properties.ordering_satisfy(order.iter().cloned())? {
844 return Ok(SortOrderPushdownResult::Exact {
845 inner: Arc::new(self.clone()) as Arc<dyn FileSource>,
846 });
847 }
848
849 // If the source's declared ordering is a non-empty *proper* prefix
850 // of the request (e.g. source `[a DESC, b ASC]`, request
851 // `[a DESC, b ASC, c DESC]`), decline pushdown so the outer
852 // `SortExec`'s `sort_prefix` optimisation — prefix-aware early
853 // termination in `TopK` — can still fire. Firing the Inexact
854 // pipeline below would invalidate the source's `output_ordering`
855 // (the runtime row-group reorder is approximate, so we can't
856 // honour the declared ordering anymore), which is exactly what
857 // `EnforceSorting` needs to derive `sort_prefix`. On data that
858 // is already in prefix order the stats-based reorder is mostly
859 // a no-op anyway, so the trade-off is plainly bad.
860 for prefix_len in 1..order.len() {
861 let prefix = order[..prefix_len].to_vec();
862 if eq_properties.ordering_satisfy(prefix.iter().cloned())? {
863 return Ok(SortOrderPushdownResult::Unsupported);
864 }
865 }
866
867 // Inexact pushdown. Two independent signals; either is enough
868 // to produce an approximate ordering, and they compose when
869 // both apply:
870 //
871 // 1. `column_in_file_schema`: the request's leading sort key is
872 // a plain `Column` present in the file schema. The opener
873 // can sort row groups by that column's `min` via parquet
874 // statistics. Drives `sort_order_for_reorder`'s actual use.
875 //
876 // 2. `reversed_satisfies`: the source's declared ordering,
877 // when reversed, satisfies the request. This is strictly
878 // more powerful than the column-in-schema check because it
879 // runs the request through `EquivalenceProperties`'s full
880 // reasoning machinery:
881 //
882 // - Function monotonicity: e.g. file declares
883 // `[extract_year_month(ws) DESC, ws DESC]`, request is
884 // `[ws ASC]`; the reversed ordering still satisfies the
885 // request via `extract_year_month`'s monotonicity even
886 // though parquet has no stats keyed by the function
887 // expression itself.

Calls 15

newFunction · 0.85
ordering_satisfyMethod · 0.80
to_vecMethod · 0.80
clear_orderingsMethod · 0.80
oeq_classMethod · 0.80
field_with_nameMethod · 0.80
is_emptyMethod · 0.45
clonedMethod · 0.45
iterMethod · 0.45
cloneMethod · 0.45
lenMethod · 0.45
mapMethod · 0.45