use of org.apache.flink.table.planner.plan.utils.NestedSchema in project flink by apache.
the class PushProjectIntoTableSourceScanRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final LogicalProject project = call.rel(0);
final LogicalTableScan scan = call.rel(1);
final TableSourceTable sourceTable = scan.getTable().unwrap(TableSourceTable.class);
final boolean supportsNestedProjection = supportsNestedProjection(sourceTable.tableSource());
final int[] refFields = RexNodeExtractor.extractRefInputFields(project.getProjects());
if (!supportsNestedProjection && refFields.length == scan.getRowType().getFieldCount()) {
// There is no top-level projection and nested projections aren't supported.
return;
}
final FlinkTypeFactory typeFactory = unwrapTypeFactory(scan);
final ResolvedSchema schema = sourceTable.contextResolvedTable().getResolvedSchema();
final RowType producedType = createProducedType(schema, sourceTable.tableSource());
final NestedSchema projectedSchema = NestedProjectionUtil.build(getProjections(project, scan), typeFactory.buildRelNodeRowType(producedType));
if (!supportsNestedProjection) {
for (NestedColumn column : projectedSchema.columns().values()) {
column.markLeaf();
}
}
final List<SourceAbilitySpec> abilitySpecs = new ArrayList<>();
final RowType newProducedType = performPushDown(sourceTable, projectedSchema, producedType, abilitySpecs);
final DynamicTableSource newTableSource = sourceTable.tableSource().copy();
final SourceAbilityContext context = SourceAbilityContext.from(scan);
abilitySpecs.forEach(spec -> spec.apply(newTableSource, context));
final RelDataType newRowType = typeFactory.buildRelNodeRowType(newProducedType);
final TableSourceTable newSource = sourceTable.copy(newTableSource, newRowType, abilitySpecs.toArray(new SourceAbilitySpec[0]));
final LogicalTableScan newScan = new LogicalTableScan(scan.getCluster(), scan.getTraitSet(), scan.getHints(), newSource);
final LogicalProject newProject = project.copy(project.getTraitSet(), newScan, rewriteProjections(call, newSource, projectedSchema), project.getRowType());
if (ProjectRemoveRule.isTrivial(newProject)) {
call.transformTo(newScan);
} else {
call.transformTo(newProject);
}
}
use of org.apache.flink.table.planner.plan.utils.NestedSchema in project flink by apache.
the class PushProjectIntoTableSourceScanRule method performPushDown.
private RowType performPushDown(TableSourceTable source, NestedSchema projectedSchema, RowType producedType, List<SourceAbilitySpec> abilitySpecs) {
final int numPhysicalColumns;
final List<NestedColumn> projectedMetadataColumns;
if (supportsMetadata(source.tableSource())) {
final List<String> declaredMetadataKeys = createRequiredMetadataKeys(source.contextResolvedTable().getResolvedSchema(), source.tableSource());
numPhysicalColumns = producedType.getFieldCount() - declaredMetadataKeys.size();
projectedMetadataColumns = IntStream.range(0, declaredMetadataKeys.size()).mapToObj(i -> producedType.getFieldNames().get(numPhysicalColumns + i)).map(fieldName -> projectedSchema.columns().get(fieldName)).filter(Objects::nonNull).collect(Collectors.toList());
} else {
numPhysicalColumns = producedType.getFieldCount();
projectedMetadataColumns = Collections.emptyList();
}
final int[][] physicalProjections;
if (supportsProjectionPushDown(source.tableSource())) {
projectedMetadataColumns.forEach(metaColumn -> projectedSchema.columns().remove(metaColumn.name()));
physicalProjections = NestedProjectionUtil.convertToIndexArray(projectedSchema);
projectedMetadataColumns.forEach(metaColumn -> projectedSchema.columns().put(metaColumn.name(), metaColumn));
} else {
physicalProjections = IntStream.range(0, numPhysicalColumns).mapToObj(columnIndex -> new int[] { columnIndex }).toArray(int[][]::new);
}
final int[][] projectedFields = Stream.concat(Stream.of(physicalProjections), projectedMetadataColumns.stream().map(NestedColumn::indexInOriginSchema).map(columnIndex -> new int[] { columnIndex })).toArray(int[][]::new);
int newIndex = physicalProjections.length;
for (NestedColumn metaColumn : projectedMetadataColumns) {
metaColumn.setIndexOfLeafInNewSchema(newIndex++);
}
if (supportsProjectionPushDown(source.tableSource())) {
final RowType projectedPhysicalType = (RowType) Projection.of(physicalProjections).project(producedType);
abilitySpecs.add(new ProjectPushDownSpec(physicalProjections, projectedPhysicalType));
}
final RowType newProducedType = (RowType) Projection.of(projectedFields).project(producedType);
if (supportsMetadata(source.tableSource())) {
final List<String> projectedMetadataKeys = projectedMetadataColumns.stream().map(NestedColumn::name).collect(Collectors.toList());
abilitySpecs.add(new ReadingMetadataSpec(projectedMetadataKeys, newProducedType));
}
return newProducedType;
}
use of org.apache.flink.table.planner.plan.utils.NestedSchema in project flink by apache.
the class ProjectWatermarkAssignerTransposeRule method matches.
@Override
public boolean matches(RelOptRuleCall call) {
LogicalProject project = call.rel(0);
LogicalWatermarkAssigner watermarkAssigner = call.rel(1);
NestedSchema usedFieldInProjectIncludingRowTimeFields = getUsedFieldsInTopLevelProjectAndWatermarkAssigner(project, watermarkAssigner);
return usedFieldInProjectIncludingRowTimeFields.columns().size() != watermarkAssigner.getRowType().getFieldCount();
}
use of org.apache.flink.table.planner.plan.utils.NestedSchema in project flink by apache.
the class ProjectWatermarkAssignerTransposeRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
LogicalProject project = call.rel(0);
LogicalWatermarkAssigner watermarkAssigner = call.rel(1);
// NOTES: DON'T use the nestedSchema datatype to build the transposed project.
NestedSchema nestedSchema = getUsedFieldsInTopLevelProjectAndWatermarkAssigner(project, watermarkAssigner);
FlinkRelBuilder builder = (FlinkRelBuilder) call.builder().push(watermarkAssigner.getInput());
List<RexInputRef> transposedProjects = new LinkedList<>();
List<String> usedNames = new LinkedList<>();
// add the used column RexInputRef and names into list
for (NestedColumn column : nestedSchema.columns().values()) {
// mark by hand
column.setIndexOfLeafInNewSchema(transposedProjects.size());
column.markLeaf();
usedNames.add(column.name());
transposedProjects.add(builder.field(column.indexInOriginSchema()));
}
// get the rowtime field index in the transposed project
String rowTimeName = watermarkAssigner.getRowType().getFieldNames().get(watermarkAssigner.rowtimeFieldIndex());
int indexOfRowTimeInTransposedProject;
if (nestedSchema.columns().get(rowTimeName) == null) {
// push the RexInputRef of the rowtime into the list
int rowTimeIndexInInput = watermarkAssigner.rowtimeFieldIndex();
indexOfRowTimeInTransposedProject = transposedProjects.size();
transposedProjects.add(builder.field(rowTimeIndexInInput));
usedNames.add(rowTimeName);
} else {
// find rowtime ref in the list and mark the location
indexOfRowTimeInTransposedProject = nestedSchema.columns().get(rowTimeName).indexOfLeafInNewSchema();
}
// the rowtime column has no rowtime indicator
builder.project(transposedProjects, usedNames);
// rewrite the top level field reference
RexNode newWatermarkExpr = watermarkAssigner.watermarkExpr().accept(new RexShuttle() {
@Override
public RexNode visitInputRef(RexInputRef inputRef) {
String fieldName = watermarkAssigner.getRowType().getFieldNames().get(inputRef.getIndex());
return builder.field(nestedSchema.columns().get(fieldName).indexOfLeafInNewSchema());
}
});
builder.watermark(indexOfRowTimeInTransposedProject, newWatermarkExpr);
List<RexNode> newProjects = NestedProjectionUtil.rewrite(project.getProjects(), nestedSchema, call.builder().getRexBuilder());
RelNode newProject = builder.project(newProjects, project.getRowType().getFieldNames()).build();
call.transformTo(newProject);
}
Aggregations