Skip to content

Commit d0f993e

Browse files
authored
[mosaic] Resolve row-group filter fields by name (#10729)
1 parent ae2ea66 commit d0f993e

2 files changed

Lines changed: 83 additions & 1 deletion

File tree

‎paimon-mosaic/src/main/java/org/apache/paimon/format/mosaic/MosaicRecordsReader.java‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.paimon.mosaic.ColumnStatistics;
3232
import org.apache.paimon.mosaic.MosaicReader;
3333
import org.apache.paimon.predicate.Predicate;
34+
import org.apache.paimon.predicate.PredicateRemapper;
3435
import org.apache.paimon.reader.FileRecordIterator;
3536
import org.apache.paimon.reader.FileRecordReader;
3637
import org.apache.paimon.table.SpecialFields;
@@ -214,7 +215,7 @@ public MosaicRecordsReader(
214215
this.inputFileAdapter = inputFileAdapter;
215216
this.dataSchemaRowType = dataSchemaRowType;
216217
this.projectedFieldCount = projectedRowType.getFieldCount();
217-
this.predicates = predicates;
218+
this.predicates = resolvePredicates(predicates, dataSchemaRowType);
218219
this.selection = selection;
219220
this.allocator = allocator;
220221

@@ -298,6 +299,28 @@ static long estimatedRowBytes(RowType projectedRowType) {
298299
return Math.max(1, bytes);
299300
}
300301

302+
/**
303+
* Resolves predicate fields by name against the file's row type. Callers such as Format Tables
304+
* and primary-key tables pass predicates whose indices refer to a different row type.
305+
*/
306+
@Nullable
307+
private static List<Predicate> resolvePredicates(
308+
@Nullable List<Predicate> predicates, RowType dataSchemaRowType) {
309+
if (predicates == null || predicates.isEmpty()) {
310+
return predicates;
311+
}
312+
List<Predicate> resolved = new ArrayList<>(predicates.size());
313+
for (Predicate predicate : predicates) {
314+
try {
315+
resolved.add(PredicateRemapper.remap(predicate, dataSchemaRowType));
316+
} catch (IllegalArgumentException e) {
317+
// The field is not in this file's row type. Dropping the conjunct only relaxes
318+
// row-group pruning.
319+
}
320+
}
321+
return resolved;
322+
}
323+
301324
int prefetchDepth() {
302325
return prefetchDepth;
303326
}

‎paimon-mosaic/src/test/java/org/apache/paimon/format/mosaic/FormatTableMosaicReadTest.java‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import org.apache.paimon.data.serializer.InternalRowSerializer;
2626
import org.apache.paimon.fs.Path;
2727
import org.apache.paimon.fs.local.LocalFileIO;
28+
import org.apache.paimon.predicate.Predicate;
29+
import org.apache.paimon.predicate.PredicateBuilder;
2830
import org.apache.paimon.reader.RecordReader;
2931
import org.apache.paimon.table.FormatTable;
3032
import org.apache.paimon.table.sink.BatchTableCommit;
@@ -40,6 +42,8 @@
4042
import org.junit.jupiter.api.Test;
4143
import org.junit.jupiter.api.io.TempDir;
4244

45+
import javax.annotation.Nullable;
46+
4347
import java.util.ArrayList;
4448
import java.util.Arrays;
4549
import java.util.Collections;
@@ -186,6 +190,53 @@ void testInvalidCompressionPropagatedFromWriter() {
186190
.hasMessageContaining("Mosaic format only supports zstd");
187191
}
188192

193+
@Test
194+
void testFilterOnDataColumnAfterPartitionColumn() throws Exception {
195+
RowType rowType = partitionFirstRowType();
196+
FormatTable table = writePartitionFirstTable(rowType, "a,b");
197+
PredicateBuilder builder = new PredicateBuilder(rowType);
198+
199+
assertThat(readAll(table, rowType, builder.equal(1, 1)))
200+
.extracting(row -> row.getInt(1))
201+
.contains(1);
202+
assertThat(readAll(table, rowType, builder.equal(2, 101)))
203+
.extracting(row -> row.getInt(2))
204+
.contains(101);
205+
assertThat(readAll(table, rowType, builder.greaterOrEqual(1, 105))).isEmpty();
206+
}
207+
208+
@Test
209+
void testFilterOnColumnWithoutStatsAfterPartitionColumn() throws Exception {
210+
RowType rowType = partitionFirstRowType();
211+
FormatTable table = writePartitionFirstTable(rowType, "b");
212+
PredicateBuilder builder = new PredicateBuilder(rowType);
213+
214+
assertThat(readAll(table, rowType, builder.equal(1, 1)))
215+
.extracting(row -> row.getInt(1))
216+
.contains(1);
217+
}
218+
219+
private static RowType partitionFirstRowType() {
220+
return RowType.builder()
221+
.field("dt", DataTypes.STRING())
222+
.field("a", DataTypes.INT())
223+
.field("b", DataTypes.INT())
224+
.build();
225+
}
226+
227+
private FormatTable writePartitionFirstTable(RowType rowType, String statsColumns)
228+
throws Exception {
229+
Map<String, String> options = new HashMap<>();
230+
options.put(MosaicFileFormat.STATS_COLUMNS.key(), statsColumns);
231+
FormatTable table = buildFormatTable(rowType, Collections.singletonList("dt"), options);
232+
List<InternalRow> rows = new ArrayList<>();
233+
for (int i = 1; i <= 10; i++) {
234+
rows.add(GenericRow.of(BinaryString.fromString("p"), i, 100 + i));
235+
}
236+
writeAll(table, rows);
237+
return table;
238+
}
239+
189240
private FormatTable buildFormatTable(
190241
RowType rowType, List<String> partitionKeys, Map<String, String> options) {
191242
String location = new Path(tempPath.toUri()).toString();
@@ -218,7 +269,15 @@ private static void writeAll(FormatTable table, List<InternalRow> rows) throws E
218269
}
219270

220271
private static List<InternalRow> readAll(FormatTable table, RowType rowType) throws Exception {
272+
return readAll(table, rowType, null);
273+
}
274+
275+
private static List<InternalRow> readAll(
276+
FormatTable table, RowType rowType, @Nullable Predicate filter) throws Exception {
221277
ReadBuilder readBuilder = table.newReadBuilder();
278+
if (filter != null) {
279+
readBuilder.withFilter(filter);
280+
}
222281
List<Split> splits = readBuilder.newScan().plan().splits();
223282
assertThat(splits).isNotEmpty();
224283

0 commit comments

Comments
 (0)