You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e98fb60
Browse filesBrowse the repository at this point in the historyBrowse files
Allow Range partitioned inputs to PartitionedTopK (apache#23355)
- Closesapache#23290.
In two commits:
* Improve the robustness of `WindowTopN` to intermediate
`RepartitionExec` nodes, to ensure that `PartitionedTopK` can still be
used when `target_partitions` mismatches physical partitions.
* Use `required_input_distributions` to declare required partitioning
for `PartitionedTopKExec`, `BoundedWindowAggExec`, and `WindowAggExec`.
Yes, new `slt` tests are added for both the `WindowTopN` robustness fix,
and for the use of `required_input_distributions` in `PartitionedTopK`.
No: only plan changes.
Copy file name to clipboardExpand all lines: datafusion/sqllogictest/test_files/range_partitioning.slt
+157Lines changed: 157 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -897,5 +897,162 @@ SELECT range_key, SUM(value) OVER (ORDER BY value) FROM range_partitioned ORDER
897
897
30 1060
898
898
35 1410
899
899
900
+
901
+
902
+
##########
903
+
# TEST 26: PartitionedTopK on Range Partition Column
904
+
# Exact Range([range_key]) satisfies the TopK partition key and avoids repartitioning.
905
+
##########
906
+
907
+
statement ok
908
+
set datafusion.optimizer.enable_window_topn = true;
909
+
910
+
statement ok
911
+
set datafusion.optimizer.subset_repartition_threshold = 4;
912
+
913
+
statement ok
914
+
set datafusion.optimizer.preserve_file_partitions = 0;
915
+
916
+
query TT
917
+
EXPLAIN SELECT * FROM (
918
+
SELECT range_key, value, ROW_NUMBER() OVER (PARTITION BY range_key ORDER BY value DESC) as rn
919
+
FROM range_partitioned
920
+
) WHERE rn <= 1;
921
+
----
922
+
physical_plan
923
+
01)ProjectionExec: expr=[range_key@0 as range_key, value@1 as value, row_number() PARTITION BY [range_partitioned.range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW@2 as rn]
924
+
02)--BoundedWindowAggExec: wdw=[row_number() PARTITION BY [range_partitioned.range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW: Field { "row_number() PARTITION BY [range_partitioned.range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW": UInt64 }, frame: RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW], mode=[Sorted]
SELECT range_key, value, ROW_NUMBER() OVER (PARTITION BY range_key ORDER BY value DESC) as rn
931
+
FROM range_partitioned
932
+
) WHERE rn <= 1
933
+
ORDER BY range_key;
934
+
----
935
+
1 10 1
936
+
5 50 1
937
+
10 100 1
938
+
15 150 1
939
+
20 200 1
940
+
25 250 1
941
+
30 300 1
942
+
35 350 1
943
+
944
+
945
+
##########
946
+
# TEST 27: PartitionedTopK on Non-Range Column
947
+
# Partitioning on a non-range key cannot reuse Range([range_key]) and
948
+
# requires hash repartitioning.
949
+
##########
950
+
951
+
statement ok
952
+
set datafusion.optimizer.subset_repartition_threshold = 4;
953
+
954
+
statement ok
955
+
set datafusion.optimizer.preserve_file_partitions = 0;
956
+
957
+
query TT
958
+
EXPLAIN SELECT * FROM (
959
+
SELECT non_range_key, value, ROW_NUMBER() OVER (PARTITION BY non_range_key ORDER BY value DESC) as rn
960
+
FROM range_partitioned
961
+
) WHERE rn <= 1;
962
+
----
963
+
physical_plan
964
+
01)ProjectionExec: expr=[non_range_key@0 as non_range_key, value@1 as value, row_number() PARTITION BY [range_partitioned.non_range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW@2 as rn]
965
+
02)--BoundedWindowAggExec: wdw=[row_number() PARTITION BY [range_partitioned.non_range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW: Field { "row_number() PARTITION BY [range_partitioned.non_range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW": UInt64 }, frame: RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW], mode=[Sorted]
SELECT non_range_key, value, ROW_NUMBER() OVER (PARTITION BY non_range_key ORDER BY value DESC) as rn
973
+
FROM range_partitioned
974
+
) WHERE rn <= 1
975
+
ORDER BY non_range_key;
976
+
----
977
+
1 300 1
978
+
2 350 1
979
+
980
+
981
+
##########
982
+
# TEST 28: PartitionedTopK Reuses Range Subset Partitioning
983
+
# With subset threshold met and preserve-file disabled, Range([range_key])
984
+
# satisfies partitioning by (range_key, non_range_key).
985
+
##########
986
+
987
+
statement ok
988
+
set datafusion.optimizer.subset_repartition_threshold = 4;
989
+
990
+
statement ok
991
+
set datafusion.optimizer.preserve_file_partitions = 0;
992
+
993
+
query TT
994
+
EXPLAIN SELECT * FROM (
995
+
SELECT range_key, non_range_key, value, ROW_NUMBER() OVER (PARTITION BY range_key, non_range_key ORDER BY value DESC) as rn
996
+
FROM range_partitioned
997
+
) WHERE rn <= 1;
998
+
----
999
+
physical_plan
1000
+
01)ProjectionExec: expr=[range_key@0 as range_key, non_range_key@1 as non_range_key, value@2 as value, row_number() PARTITION BY [range_partitioned.range_key, range_partitioned.non_range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW@3 as rn]
1001
+
02)--BoundedWindowAggExec: wdw=[row_number() PARTITION BY [range_partitioned.range_key, range_partitioned.non_range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW: Field { "row_number() PARTITION BY [range_partitioned.range_key, range_partitioned.non_range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW": UInt64 }, frame: RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW], mode=[Sorted]
SELECT range_key, non_range_key, value, ROW_NUMBER() OVER (PARTITION BY range_key, non_range_key ORDER BY value DESC) as rn
1008
+
FROM range_partitioned
1009
+
) WHERE rn <= 1
1010
+
ORDER BY range_key, non_range_key;
1011
+
----
1012
+
1 1 10 1
1013
+
5 2 50 1
1014
+
10 1 100 1
1015
+
15 2 150 1
1016
+
20 1 200 1
1017
+
25 2 250 1
1018
+
30 1 300 1
1019
+
35 2 350 1
1020
+
1021
+
1022
+
##########
1023
+
# TEST 29: Range Subset PartitionedTopK Rehashes Below Subset Threshold
1024
+
# Range([range_key]) is only a subset of PARTITION BY (range_key, non_range_key),
1025
+
# so it should not satisfy the TopK partition key when subset satisfaction is
1026
+
# disabled.
1027
+
##########
1028
+
1029
+
statement ok
1030
+
set datafusion.execution.target_partitions = 4;
1031
+
1032
+
statement ok
1033
+
set datafusion.optimizer.subset_repartition_threshold = 5;
1034
+
1035
+
statement ok
1036
+
set datafusion.optimizer.preserve_file_partitions = 0;
1037
+
1038
+
query TT
1039
+
EXPLAIN SELECT * FROM (
1040
+
SELECT range_key, non_range_key, value, ROW_NUMBER() OVER (PARTITION BY range_key, non_range_key ORDER BY value DESC) as rn
1041
+
FROM range_partitioned
1042
+
) WHERE rn <= 1;
1043
+
----
1044
+
physical_plan
1045
+
01)ProjectionExec: expr=[range_key@0 as range_key, non_range_key@1 as non_range_key, value@2 as value, row_number() PARTITION BY [range_partitioned.range_key, range_partitioned.non_range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW@3 as rn]
1046
+
02)--BoundedWindowAggExec: wdw=[row_number() PARTITION BY [range_partitioned.range_key, range_partitioned.non_range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW: Field { "row_number() PARTITION BY [range_partitioned.range_key, range_partitioned.non_range_key] ORDER BY [range_partitioned.value DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW": UInt64 }, frame: RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW], mode=[Sorted]
set datafusion.optimizer.repartition_windows = false;
636
+
637
+
statement ok
638
+
set datafusion.execution.batch_size = 1;
639
+
640
+
statement ok
641
+
set datafusion.optimizer.enable_window_topn = true;
642
+
643
+
query TT
644
+
EXPLAIN SELECT * FROM (
645
+
SELECT c1, c2, ROW_NUMBER() OVER (PARTITION BY c1 ORDER BY c2 DESC) as rn
646
+
FROM t
647
+
) WHERE rn <= 1;
648
+
----
649
+
logical_plan
650
+
01)Projection: t.c1, t.c2, row_number() PARTITION BY [t.c1] ORDER BY [t.c2 DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW AS rn
651
+
02)--Filter: row_number() PARTITION BY [t.c1] ORDER BY [t.c2 DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW <= UInt64(1)
652
+
03)----WindowAggr: windowExpr=[[row_number() PARTITION BY [t.c1] ORDER BY [t.c2 DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW]]
653
+
04)------TableScan: t projection=[c1, c2]
654
+
physical_plan
655
+
01)ProjectionExec: expr=[c1@0 as c1, c2@1 as c2, row_number() PARTITION BY [t.c1] ORDER BY [t.c2 DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW@2 as rn]
03)----BoundedWindowAggExec: wdw=[row_number() PARTITION BY [t.c1] ORDER BY [t.c2 DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW: Field { "row_number() PARTITION BY [t.c1] ORDER BY [t.c2 DESC NULLS FIRST] RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW": UInt64 }, frame: RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW], mode=[Sorted]
0 commit comments