34
34
import com .google .common .collect .Lists ;
35
35
36
36
import java .util .List ;
37
+ import java .util .Optional ;
37
38
import java .util .stream .Collectors ;
38
39
39
40
/**
@@ -55,7 +56,11 @@ public List<Rule> buildRules() {
55
56
>= limit .getLimit () + limit .getOffset ())
56
57
.then (limit -> {
57
58
LogicalAggregate <? extends Plan > agg = limit .child ();
58
- List <OrderKey > orderKeys = generateOrderKeyByGroupKey (agg );
59
+ Optional <OrderKey > orderKeysOpt = tryGenerateOrderKeyByTheFirstGroupKey (agg );
60
+ if (!orderKeysOpt .isPresent ()) {
61
+ return null ;
62
+ }
63
+ List <OrderKey > orderKeys = Lists .newArrayList (orderKeysOpt .get ());
59
64
return new LogicalTopN <>(orderKeys , limit .getLimit (), limit .getOffset (), agg );
60
65
}).toRule (RuleType .LIMIT_AGG_TO_TOPN_AGG ),
61
66
//limit->project->agg to topn->project->agg
@@ -68,7 +73,11 @@ public List<Rule> buildRules() {
68
73
LogicalProject <? extends Plan > project = limit .child ();
69
74
LogicalAggregate <? extends Plan > agg
70
75
= (LogicalAggregate <? extends Plan >) project .child ();
71
- List <OrderKey > orderKeys = generateOrderKeyByGroupKey (agg );
76
+ Optional <OrderKey > orderKeysOpt = tryGenerateOrderKeyByTheFirstGroupKey (agg );
77
+ if (!orderKeysOpt .isPresent ()) {
78
+ return null ;
79
+ }
80
+ List <OrderKey > orderKeys = Lists .newArrayList (orderKeysOpt .get ());
72
81
Plan result ;
73
82
74
83
if (outputAllGroupKeys (limit , agg )) {
@@ -78,21 +87,27 @@ public List<Rule> buildRules() {
78
87
// add the first group by key to topn, and prune this key by upper project
79
88
// topn order keys are prefix of group by keys
80
89
// refer to PushTopnToAgg.tryGenerateOrderKeyByGroupKeyAndTopnKey()
81
- List <NamedExpression > bottomProjections = Lists .newArrayList (project .getProjects ());
82
- if (agg .getGroupByExpressions ().isEmpty ()) {
83
- return null ;
84
- }
85
90
Expression firstGroupByKey = agg .getGroupByExpressions ().get (0 );
86
91
if (!(firstGroupByKey instanceof SlotReference )) {
87
92
return null ;
88
93
}
89
- bottomProjections .add ((SlotReference ) firstGroupByKey );
90
- LogicalProject <Plan > bottomProject = project .withProjects (bottomProjections );
94
+ boolean shouldPruneFirstGroupByKey = true ;
95
+ if (project .getOutputs ().contains (firstGroupByKey )) {
96
+ shouldPruneFirstGroupByKey = false ;
97
+ } else {
98
+ List <NamedExpression > bottomProjections = Lists .newArrayList (project .getProjects ());
99
+ bottomProjections .add ((SlotReference ) firstGroupByKey );
100
+ project = project .withProjects (bottomProjections );
101
+ }
91
102
LogicalTopN topn = new LogicalTopN <>(orderKeys , limit .getLimit (),
92
- limit .getOffset (), bottomProject );
93
- List <NamedExpression > limitOutput = limit .getOutput ().stream ()
94
- .map (e -> (NamedExpression ) e ).collect (Collectors .toList ());
95
- result = new LogicalProject <>(limitOutput , topn );
103
+ limit .getOffset (), project );
104
+ if (shouldPruneFirstGroupByKey ) {
105
+ List <NamedExpression > limitOutput = limit .getOutput ().stream ()
106
+ .map (e -> (NamedExpression ) e ).collect (Collectors .toList ());
107
+ result = new LogicalProject <>(limitOutput , topn );
108
+ } else {
109
+ result = topn ;
110
+ }
96
111
}
97
112
return result ;
98
113
}).toRule (RuleType .LIMIT_AGG_TO_TOPN_AGG ),
@@ -138,9 +153,14 @@ private boolean outputAllGroupKeys(LogicalLimit limit, LogicalAggregate agg) {
138
153
return limit .getOutputSet ().containsAll (agg .getGroupByExpressions ());
139
154
}
140
155
141
- private List <OrderKey > generateOrderKeyByGroupKey (LogicalAggregate <? extends Plan > agg ) {
142
- return agg .getGroupByExpressions ().stream ()
143
- .map (key -> new OrderKey (key , true , false ))
144
- .collect (Collectors .toList ());
156
+ private Optional <OrderKey > tryGenerateOrderKeyByTheFirstGroupKey (LogicalAggregate <? extends Plan > agg ) {
157
+ if (agg .getGroupByExpressions ().isEmpty ()) {
158
+ return Optional .empty ();
159
+ }
160
+ if (agg .getGroupByExpressions ().get (0 ) instanceof SlotReference ) {
161
+ // agg normalize projects the expression under agg. we cannot use it as order key above agg
162
+ return Optional .of (new OrderKey (agg .getGroupByExpressions ().get (0 ), true , false ));
163
+ }
164
+ return Optional .empty ();
145
165
}
146
166
}
0 commit comments