use of org.apache.calcite.rel.core.Window in project calcite by apache.
the class ProjectWindowTransposeRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final LogicalProject project = call.rel(0);
final LogicalWindow window = call.rel(1);
final RelOptCluster cluster = window.getCluster();
final List<RelDataTypeField> rowTypeWindowInput = window.getInput().getRowType().getFieldList();
final int windowInputColumn = rowTypeWindowInput.size();
// Record the window input columns which are actually referred
// either in the LogicalProject above LogicalWindow or LogicalWindow itself
// (Note that the constants used in LogicalWindow are not considered here)
final ImmutableBitSet beReferred = findReference(project, window);
// it is impossible to trim anyone of them out
if (beReferred.cardinality() == windowInputColumn) {
return;
}
// Put a DrillProjectRel below LogicalWindow
final List<RexNode> exps = new ArrayList<>();
final RelDataTypeFactory.Builder builder = cluster.getTypeFactory().builder();
// Keep only the fields which are referred
for (int index : BitSets.toIter(beReferred)) {
final RelDataTypeField relDataTypeField = rowTypeWindowInput.get(index);
exps.add(new RexInputRef(index, relDataTypeField.getType()));
builder.add(relDataTypeField);
}
final LogicalProject projectBelowWindow = new LogicalProject(cluster, window.getTraitSet(), window.getInput(), exps, builder.build());
// Create a new LogicalWindow with necessary inputs only
final List<Window.Group> groups = new ArrayList<>();
// As the un-referred columns are trimmed by the LogicalProject,
// the indices specified in LogicalWindow would need to be adjusted
final RexShuttle indexAdjustment = new RexShuttle() {
@Override
public RexNode visitInputRef(RexInputRef inputRef) {
final int newIndex = getAdjustedIndex(inputRef.getIndex(), beReferred, windowInputColumn);
return new RexInputRef(newIndex, inputRef.getType());
}
@Override
public RexNode visitCall(final RexCall call) {
if (call instanceof Window.RexWinAggCall) {
boolean[] update = { false };
final List<RexNode> clonedOperands = visitList(call.operands, update);
if (update[0]) {
return new Window.RexWinAggCall((SqlAggFunction) call.getOperator(), call.getType(), clonedOperands, ((Window.RexWinAggCall) call).ordinal, ((Window.RexWinAggCall) call).distinct);
} else {
return call;
}
} else {
return super.visitCall(call);
}
}
};
int aggCallIndex = windowInputColumn;
final RelDataTypeFactory.Builder outputBuilder = cluster.getTypeFactory().builder();
outputBuilder.addAll(projectBelowWindow.getRowType().getFieldList());
for (Window.Group group : window.groups) {
final ImmutableBitSet.Builder keys = ImmutableBitSet.builder();
final List<RelFieldCollation> orderKeys = new ArrayList<>();
final List<Window.RexWinAggCall> aggCalls = new ArrayList<>();
// Adjust keys
for (int index : group.keys) {
keys.set(getAdjustedIndex(index, beReferred, windowInputColumn));
}
// Adjust orderKeys
for (RelFieldCollation relFieldCollation : group.orderKeys.getFieldCollations()) {
final int index = relFieldCollation.getFieldIndex();
orderKeys.add(relFieldCollation.copy(getAdjustedIndex(index, beReferred, windowInputColumn)));
}
// Adjust Window Functions
for (Window.RexWinAggCall rexWinAggCall : group.aggCalls) {
aggCalls.add((Window.RexWinAggCall) rexWinAggCall.accept(indexAdjustment));
final RelDataTypeField relDataTypeField = window.getRowType().getFieldList().get(aggCallIndex);
outputBuilder.add(relDataTypeField);
++aggCallIndex;
}
groups.add(new Window.Group(keys.build(), group.isRows, group.lowerBound, group.upperBound, RelCollations.of(orderKeys), aggCalls));
}
final LogicalWindow newLogicalWindow = LogicalWindow.create(window.getTraitSet(), projectBelowWindow, window.constants, outputBuilder.build(), groups);
// Modify the top LogicalProject
final List<RexNode> topProjExps = new ArrayList<>();
for (RexNode rexNode : project.getChildExps()) {
topProjExps.add(rexNode.accept(indexAdjustment));
}
final LogicalProject newTopProj = project.copy(newLogicalWindow.getTraitSet(), newLogicalWindow, topProjExps, project.getRowType());
if (ProjectRemoveRule.isTrivial(newTopProj)) {
call.transformTo(newLogicalWindow);
} else {
call.transformTo(newTopProj);
}
}
use of org.apache.calcite.rel.core.Window in project drill by axbaretto.
the class DrillWindowRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final Window window = call.rel(0);
final RelNode input = call.rel(1);
final RelTraitSet traits = window.getTraitSet().plus(DrillRel.DRILL_LOGICAL).simplify();
final RelNode convertedInput = convert(input, traits);
call.transformTo(new DrillWindowRel(window.getCluster(), traits, convertedInput, window.constants, window.getRowType(), window.groups));
}
use of org.apache.calcite.rel.core.Window in project drill by apache.
the class WindowPrule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final DrillWindowRel window = call.rel(0);
RelNode input = call.rel(1);
// TODO: Order window based on existing partition by
// input.getTraitSet().subsumes()
boolean partitionby = false;
boolean addMerge = false;
// The start index of the constant fields of DrillWindowRel
final int startConstantsIndex = window.getInput().getRowType().getFieldCount();
int constantShiftIndex = 0;
for (final Ord<Window.Group> w : Ord.zip(window.groups)) {
Window.Group windowBase = w.getValue();
RelTraitSet traits = call.getPlanner().emptyTraitSet().plus(Prel.DRILL_PHYSICAL);
// For empty Over-Clause
if (windowBase.keys.isEmpty() && windowBase.orderKeys.getFieldCollations().isEmpty()) {
DrillDistributionTrait distEmptyKeys = new DrillDistributionTrait(DrillDistributionTrait.DistributionType.SINGLETON);
traits = traits.plus(distEmptyKeys);
} else if (windowBase.keys.size() > 0) {
DrillDistributionTrait distOnAllKeys = new DrillDistributionTrait(DrillDistributionTrait.DistributionType.HASH_DISTRIBUTED, ImmutableList.copyOf(getDistributionFields(windowBase)));
partitionby = true;
traits = traits.plus(distOnAllKeys);
} else if (windowBase.orderKeys.getFieldCollations().size() > 0) {
// if only the order-by clause is specified, there is a single partition
// consisting of all the rows, so we do a distributed sort followed by a
// single merge as the input of the window operator
DrillDistributionTrait distKeys = new DrillDistributionTrait(DrillDistributionTrait.DistributionType.HASH_DISTRIBUTED, ImmutableList.copyOf(getDistributionFieldsFromCollation(windowBase)));
traits = traits.plus(distKeys);
if (!isSingleMode(call)) {
addMerge = true;
}
}
// Add collation trait if either partition-by or order-by is specified.
if (partitionby || windowBase.orderKeys.getFieldCollations().size() > 0) {
RelCollation collation = getCollation(windowBase);
traits = traits.plus(collation);
}
RelNode convertedInput = convert(input, traits);
if (addMerge) {
traits = traits.plus(DrillDistributionTrait.SINGLETON);
convertedInput = new SingleMergeExchangePrel(window.getCluster(), traits, convertedInput, windowBase.collation());
}
List<RelDataTypeField> newRowFields = Lists.newArrayList();
newRowFields.addAll(convertedInput.getRowType().getFieldList());
Iterable<RelDataTypeField> newWindowFields = Iterables.filter(window.getRowType().getFieldList(), new Predicate<RelDataTypeField>() {
@Override
public boolean apply(RelDataTypeField relDataTypeField) {
return relDataTypeField.getName().startsWith("w" + w.i + "$");
}
});
for (RelDataTypeField newField : newWindowFields) {
newRowFields.add(newField);
}
RelDataType rowType = new RelRecordType(newRowFields);
List<Window.RexWinAggCall> newWinAggCalls = Lists.newArrayList();
for (Ord<Window.RexWinAggCall> aggOrd : Ord.zip(windowBase.aggCalls)) {
Window.RexWinAggCall aggCall = aggOrd.getValue();
// If the argument points at the constant and
// additional fields have been generated by the Window below,
// the index of constants will be shifted
final List<RexNode> newOperandsOfWindowFunction = Lists.newArrayList();
for (RexNode operand : aggCall.getOperands()) {
if (operand instanceof RexInputRef) {
final RexInputRef rexInputRef = (RexInputRef) operand;
final int refIndex = rexInputRef.getIndex();
// Check if this RexInputRef points at the constants
if (rexInputRef.getIndex() >= startConstantsIndex) {
operand = new RexInputRef(refIndex + constantShiftIndex, window.constants.get(refIndex - startConstantsIndex).getType());
}
}
newOperandsOfWindowFunction.add(operand);
}
aggCall = new Window.RexWinAggCall((SqlAggFunction) aggCall.getOperator(), aggCall.getType(), newOperandsOfWindowFunction, aggCall.ordinal, aggCall.distinct);
newWinAggCalls.add(new Window.RexWinAggCall((SqlAggFunction) aggCall.getOperator(), aggCall.getType(), aggCall.getOperands(), aggOrd.i, aggCall.distinct));
}
windowBase = new Window.Group(windowBase.keys, windowBase.isRows, windowBase.lowerBound, windowBase.upperBound, windowBase.orderKeys, newWinAggCalls);
input = new WindowPrel(window.getCluster(), window.getTraitSet().merge(traits), convertedInput, window.getConstants(), rowType, windowBase);
constantShiftIndex += windowBase.aggCalls.size();
}
call.transformTo(input);
}
use of org.apache.calcite.rel.core.Window in project drill by apache.
the class DrillWindowRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final Window window = call.rel(0);
final RelNode input = call.rel(1);
final RelTraitSet traits = window.getTraitSet().plus(DrillRel.DRILL_LOGICAL).simplify();
final RelNode convertedInput = convert(input, traits);
call.transformTo(new DrillWindowRel(window.getCluster(), traits, convertedInput, window.constants, window.getRowType(), window.groups));
}
use of org.apache.calcite.rel.core.Window in project drill by axbaretto.
the class WindowPrule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final DrillWindowRel window = call.rel(0);
RelNode input = call.rel(1);
// TODO: Order window based on existing partition by
// input.getTraitSet().subsumes()
boolean partitionby = false;
boolean addMerge = false;
// The start index of the constant fields of DrillWindowRel
final int startConstantsIndex = window.getInput().getRowType().getFieldCount();
int constantShiftIndex = 0;
for (final Ord<Window.Group> w : Ord.zip(window.groups)) {
Window.Group windowBase = w.getValue();
RelTraitSet traits = call.getPlanner().emptyTraitSet().plus(Prel.DRILL_PHYSICAL);
// For empty Over-Clause
if (windowBase.keys.isEmpty() && windowBase.orderKeys.getFieldCollations().isEmpty()) {
DrillDistributionTrait distEmptyKeys = new DrillDistributionTrait(DrillDistributionTrait.DistributionType.SINGLETON);
traits = traits.plus(distEmptyKeys);
} else if (windowBase.keys.size() > 0) {
DrillDistributionTrait distOnAllKeys = new DrillDistributionTrait(DrillDistributionTrait.DistributionType.HASH_DISTRIBUTED, ImmutableList.copyOf(getDistributionFields(windowBase)));
partitionby = true;
traits = traits.plus(distOnAllKeys);
} else if (windowBase.orderKeys.getFieldCollations().size() > 0) {
// if only the order-by clause is specified, there is a single partition
// consisting of all the rows, so we do a distributed sort followed by a
// single merge as the input of the window operator
DrillDistributionTrait distKeys = new DrillDistributionTrait(DrillDistributionTrait.DistributionType.HASH_DISTRIBUTED, ImmutableList.copyOf(getDistributionFieldsFromCollation(windowBase)));
traits = traits.plus(distKeys);
if (!isSingleMode(call)) {
addMerge = true;
}
}
// Add collation trait if either partition-by or order-by is specified.
if (partitionby || windowBase.orderKeys.getFieldCollations().size() > 0) {
RelCollation collation = getCollation(windowBase);
traits = traits.plus(collation);
}
RelNode convertedInput = convert(input, traits);
if (addMerge) {
traits = traits.plus(DrillDistributionTrait.SINGLETON);
convertedInput = new SingleMergeExchangePrel(window.getCluster(), traits, convertedInput, windowBase.collation());
}
List<RelDataTypeField> newRowFields = Lists.newArrayList();
for (RelDataTypeField field : convertedInput.getRowType().getFieldList()) {
newRowFields.add(field);
}
Iterable<RelDataTypeField> newWindowFields = Iterables.filter(window.getRowType().getFieldList(), new Predicate<RelDataTypeField>() {
@Override
public boolean apply(RelDataTypeField relDataTypeField) {
return relDataTypeField.getName().startsWith("w" + w.i + "$");
}
});
for (RelDataTypeField newField : newWindowFields) {
newRowFields.add(newField);
}
RelDataType rowType = new RelRecordType(newRowFields);
List<Window.RexWinAggCall> newWinAggCalls = Lists.newArrayList();
for (Ord<Window.RexWinAggCall> aggOrd : Ord.zip(windowBase.aggCalls)) {
Window.RexWinAggCall aggCall = aggOrd.getValue();
// If the argument points at the constant and
// additional fields have been generated by the Window below,
// the index of constants will be shifted
final List<RexNode> newOperandsOfWindowFunction = Lists.newArrayList();
for (RexNode operand : aggCall.getOperands()) {
if (operand instanceof RexInputRef) {
final RexInputRef rexInputRef = (RexInputRef) operand;
final int refIndex = rexInputRef.getIndex();
// Check if this RexInputRef points at the constants
if (rexInputRef.getIndex() >= startConstantsIndex) {
operand = new RexInputRef(refIndex + constantShiftIndex, window.constants.get(refIndex - startConstantsIndex).getType());
}
}
newOperandsOfWindowFunction.add(operand);
}
aggCall = new Window.RexWinAggCall((SqlAggFunction) aggCall.getOperator(), aggCall.getType(), newOperandsOfWindowFunction, aggCall.ordinal, aggCall.distinct);
newWinAggCalls.add(new Window.RexWinAggCall((SqlAggFunction) aggCall.getOperator(), aggCall.getType(), aggCall.getOperands(), aggOrd.i, aggCall.distinct));
}
windowBase = new Window.Group(windowBase.keys, windowBase.isRows, windowBase.lowerBound, windowBase.upperBound, windowBase.orderKeys, newWinAggCalls);
input = new WindowPrel(window.getCluster(), window.getTraitSet().merge(traits), convertedInput, window.getConstants(), rowType, windowBase);
constantShiftIndex += windowBase.aggCalls.size();
}
call.transformTo(input);
}
Aggregations