|
18 | 18 | */
|
19 | 19 | package org.apache.iceberg.spark.source;
|
20 | 20 |
|
| 21 | +import java.util.Arrays; |
21 | 22 | import org.apache.iceberg.DistributionMode;
|
22 | 23 | import org.apache.iceberg.IsolationLevel;
|
23 | 24 | import org.apache.iceberg.PartitionSpec;
|
|
34 | 35 | import org.apache.iceberg.spark.SparkUtil;
|
35 | 36 | import org.apache.iceberg.spark.SparkWriteConf;
|
36 | 37 | import org.apache.iceberg.types.TypeUtil;
|
| 38 | +import org.apache.iceberg.util.SortOrderUtil; |
37 | 39 | import org.apache.spark.sql.SparkSession;
|
38 | 40 | import org.apache.spark.sql.connector.distributions.Distribution;
|
39 | 41 | import org.apache.spark.sql.connector.distributions.Distributions;
|
| 42 | +import org.apache.spark.sql.connector.distributions.OrderedDistribution; |
40 | 43 | import org.apache.spark.sql.connector.expressions.SortOrder;
|
41 | 44 | import org.apache.spark.sql.connector.iceberg.write.RowLevelOperation.Command;
|
42 | 45 | import org.apache.spark.sql.connector.read.Scan;
|
@@ -163,6 +166,22 @@ public Write build() {
|
163 | 166 | ordering = NO_ORDERING;
|
164 | 167 | }
|
165 | 168 |
|
| 169 | + // In case of CopyOnWrite operation with scan using file as split and OrderedDistribution |
| 170 | + // * skip ordering by partition, iff, all input data files are in same partition and has same |
| 171 | + // spec as current |
| 172 | + // table spec |
| 173 | + // * skip ordering by table sort order, iff, all input files are already sorted by table's |
| 174 | + // current sort order |
| 175 | + if (copyOnWriteScan != null |
| 176 | + && copyOnWriteScan.fileAsSplit() |
| 177 | + && distribution instanceof OrderedDistribution) { |
| 178 | + if (skipOrderingAndDistribution((OrderedDistribution) distribution)) { |
| 179 | + LOG.info( |
| 180 | + "Skipping distribution/ordering: input files are already in required distribution/ordering"); |
| 181 | + ordering = NO_ORDERING; |
| 182 | + distribution = Distributions.unspecified(); |
| 183 | + } |
| 184 | + } |
166 | 185 | return new SparkWrite(
|
167 | 186 | spark, table, writeConf, writeInfo, appId, writeSchema, dsSchema, distribution, ordering) {
|
168 | 187 |
|
@@ -265,4 +284,26 @@ private static Schema validateOrMergeWriteSchema(
|
265 | 284 |
|
266 | 285 | return writeSchema;
|
267 | 286 | }
|
| 287 | + |
| 288 | + private boolean skipOrderingAndDistribution(OrderedDistribution distribution) { |
| 289 | + // check if all input files have same partitioning as current table partitioning |
| 290 | + if (!copyOnWriteScan.files().stream() |
| 291 | + .allMatch(x -> x.file().specId() == table.spec().specId())) { |
| 292 | + return false; |
| 293 | + } |
| 294 | + |
| 295 | + // check if all input files are sorted on table's current sort order |
| 296 | + if (!copyOnWriteScan.files().stream() |
| 297 | + .allMatch( |
| 298 | + x -> |
| 299 | + x.file().sortOrderId() != null |
| 300 | + && x.file().sortOrderId() == table.sortOrder().orderId())) { |
| 301 | + return false; |
| 302 | + } |
| 303 | + |
| 304 | + // check if required ordering is same as table's default ordering |
| 305 | + return Arrays.equals( |
| 306 | + distribution.ordering(), |
| 307 | + SparkDistributionAndOrderingUtil.convert(SortOrderUtil.buildSortOrder(table))); |
| 308 | + } |
268 | 309 | }
|
0 commit comments