55
66package org .opensearch .sql .opensearch .planner .rules ;
77
8- import java .util .ArrayList ;
98import java .util .List ;
109import java .util .Set ;
1110import java .util .function .Predicate ;
2726import org .apache .logging .log4j .LogManager ;
2827import org .apache .logging .log4j .Logger ;
2928import org .immutables .value .Value ;
29+ import org .opensearch .ml .repackage .com .google .common .collect .Streams ;
3030import org .opensearch .sql .calcite .plan .OpenSearchRuleConfig ;
3131import org .opensearch .sql .calcite .utils .PlanUtils ;
3232import org .opensearch .sql .opensearch .storage .scan .AbstractCalciteIndexScan ;
@@ -81,13 +81,9 @@ protected void apply(
8181 // TODO https://github.com/opensearch-project/sql/issues/4564
8282 return ;
8383 }
84- List <Integer > dedupColumnIndicesInWindowProject =
85- dedupColumns .stream ()
86- .filter (rex -> rex .isA (SqlKind .INPUT_REF ))
87- .map (r -> ((RexInputRef ) r ).getIndex ())
88- .toList ();
84+ List <Integer > dedupColumnIndices = getInputRefIndices (dedupColumns );
8985 List <String > dedupColumnNames =
90- dedupColumnIndicesInWindowProject .stream ()
86+ dedupColumnIndices .stream ()
9187 .map (
9288 i ->
9389 projectWithWindow .getNamedProjects ().stream ()
@@ -107,58 +103,26 @@ protected void apply(
107103 // We convert the dedup pushdown to composite aggregate + top_hits:
108104 // Aggregate(literalAgg(dedupNumer), groups)
109105 // +- Project(groups, remaining)
110- // +- Scan or Project with expression
111106 RelBuilder relBuilder = call .builder ();
112107 // 1 Initial a RelBuilder by pushing Scan and Project
113108 if (projectWithExpr == null ) {
114- // 1.1 if projectWithExpr not existed, push scan
109+ // 1.1 if projectWithExpr not existed, push a scan then create a new project
115110 relBuilder .push (scan );
116- // 1.2 To baseline the rowType, merge the fields() and projectWithWindow
117- List <RexNode > columnsMerged = new ArrayList <>();
118- List <String > colNamesMerged = new ArrayList <>();
119111 List <RexNode > columnsFromScan = relBuilder .fields ();
120- List <RexNode > columnsFromWindowProj = projectWithWindow .getProjects ();
121112 List <String > colNamesFromScan = relBuilder .peek ().getRowType ().getFieldNames ();
122- List <String > colNamesFromWindowProj = projectWithWindow .getRowType ().getFieldNames ();
123-
124- // 1.3 Add existing columns with proper names
125- // For rename case: source = t | rename old as new | dedup new
126- // Add the column `old` with name "new"
127- for (RexNode col : columnsFromScan ) {
128- columnsMerged .add (col );
129- int projectIndex = columnsFromWindowProj .indexOf (col );
130- if (projectIndex >= 0 ) {
131- colNamesMerged .add (colNamesFromWindowProj .get (projectIndex ));
132- } else {
133- colNamesMerged .add (colNamesFromScan .get (columnsFromScan .indexOf (col )));
134- }
135- }
136- // 1.4 Append new columns from project (excluding ROW_NUMBER and duplicates)
137- for (RexNode col : columnsFromWindowProj ) {
138- if (!col .isA (SqlKind .ROW_NUMBER ) && !columnsFromScan .contains (col )) {
139- columnsMerged .add (col );
140- colNamesMerged .add (col .toString ());
141- }
142- }
143- // 1.5 if reorder required, build the reordered project
144- List <Pair <RexNode , String >> merged =
145- IntStream .range (0 , columnsMerged .size ())
146- .mapToObj (i -> new Pair <>(columnsMerged .get (i ), colNamesMerged .get (i )))
147- .toList ();
113+ List <Pair <RexNode , String >> namedPairFromScan =
114+ Streams .zip (columnsFromScan .stream (), colNamesFromScan .stream (), Pair ::new ).toList ();
148115 List <Pair <RexNode , String >> reordered =
149- moveForwardDedupColumns (merged , dedupColumnIndicesInWindowProject , dedupColumnNames );
150- // 1.6 force add this reordered project
116+ advanceDedupColumns (namedPairFromScan , dedupColumnIndices , dedupColumnNames );
151117 relBuilder .project (
152118 reordered .stream ().map (Pair ::getKey ).toList (),
153119 reordered .stream ().map (Pair ::getValue ).toList (),
154120 true );
155121 } else {
156- // 1.7 if projectWithExpr existed, push a reordered projectWithExpr
122+ // 1.2 if projectWithExpr existed, push a reordered projectWithExpr
157123 List <Pair <RexNode , String >> reordered =
158- moveForwardDedupColumns (
159- projectWithExpr .getNamedProjects (),
160- dedupColumnIndicesInWindowProject ,
161- dedupColumnNames );
124+ advanceDedupColumns (
125+ projectWithExpr .getNamedProjects (), dedupColumnIndices , dedupColumnNames );
162126 LogicalProject reorderedProject =
163127 LogicalProject .create (
164128 projectWithExpr .getInput (),
@@ -191,8 +155,22 @@ protected void apply(
191155 }
192156 }
193157
194- /** Move the dedup columns to the front of the original column list. */
195- private static List <Pair <RexNode , String >> moveForwardDedupColumns (
158+ private static List <Integer > getInputRefIndices (List <RexNode > columns ) {
159+ return columns .stream ()
160+ .filter (rex -> rex .isA (SqlKind .INPUT_REF ))
161+ .map (r -> ((RexInputRef ) r ).getIndex ())
162+ .toList ();
163+ }
164+
165+ /**
166+ * Move the dedup columns to the front of the original column list.
167+ *
168+ * @param originalColumnList The original column pair list
169+ * @param dedupColumnIndices The indices of dedup columns
170+ * @param dedupColumnNames The names of dedup columns
171+ * @return The reordered column pair list
172+ */
173+ private static List <Pair <RexNode , String >> advanceDedupColumns (
196174 List <Pair <RexNode , String >> originalColumnList ,
197175 List <Integer > dedupColumnIndices ,
198176 List <String > dedupColumnNames ) {
0 commit comments