Java Code Examples for org.apache.calcite.rel.core.JoinRelType#LEFT

The following examples show how to use org.apache.calcite.rel.core.JoinRelType#LEFT . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: EnumerableBatchNestedLoopJoinRule.java    From calcite with Apache License 2.0 5 votes vote down vote up
@Override public boolean matches(RelOptRuleCall call) {
  Join join = call.rel(0);
  JoinRelType joinType = join.getJoinType();
  return joinType == JoinRelType.INNER
      || joinType == JoinRelType.LEFT
      || joinType == JoinRelType.ANTI
      || joinType == JoinRelType.SEMI;
}
 
Example 2
Source File: PigRelOpVisitor.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Decides the join type from the inner types of both relation.
 *
 * @param leftInner  true if the left requires inner
 * @param rightInner true if the right requires inner
 * @return The join type, either INNER, LEFT, RIGHT, or FULL
 */
private static JoinRelType getJoinType(boolean leftInner, boolean rightInner) {
  if (leftInner && rightInner) {
    return JoinRelType.INNER;
  } else if (leftInner) {
    return JoinRelType.LEFT;
  } else if (rightInner) {
    return JoinRelType.RIGHT;
  } else {
    return JoinRelType.FULL;
  }
}
 
Example 3
Source File: JoinToMultiJoinRule.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Combines the join filters from the left and right inputs (if they are
 * MultiJoinRels) with the join filter in the joinrel into a single AND'd
 * join filter, unless the inputs correspond to null generating inputs in an
 * outer join
 *
 * @param joinRel join rel
 * @param left    left child of the join
 * @param right   right child of the join
 * @return combined join filters AND-ed together
 */
private List<RexNode> combineJoinFilters(
    Join joinRel,
    RelNode left,
    RelNode right) {
  JoinRelType joinType = joinRel.getJoinType();

  // AND the join condition if this isn't a left or right outer join;
  // in those cases, the outer join condition is already tracked
  // separately
  final List<RexNode> filters = new ArrayList<>();
  if ((joinType != JoinRelType.LEFT) && (joinType != JoinRelType.RIGHT)) {
    filters.add(joinRel.getCondition());
  }
  if (canCombine(left, joinType.generatesNullsOnLeft())) {
    filters.add(((MultiJoin) left).getJoinFilter());
  }
  // Need to adjust the RexInputs of the right child, since
  // those need to shift over to the right
  if (canCombine(right, joinType.generatesNullsOnRight())) {
    MultiJoin multiJoin = (MultiJoin) right;
    filters.add(
        shiftRightFilter(joinRel, left, multiJoin,
            multiJoin.getJoinFilter()));
  }

  return filters;
}
 
Example 4
Source File: JoinPruleBase.java    From Bats with Apache License 2.0 5 votes vote down vote up
protected boolean checkBroadcastConditions(RelOptPlanner planner, DrillJoin join, RelNode left, RelNode right) {

    double estimatedRightRowCount = RelMetadataQuery.instance().getRowCount(right);
    if (estimatedRightRowCount < PrelUtil.getSettings(join.getCluster()).getBroadcastThreshold()
        && ! left.getTraitSet().getTrait(DrillDistributionTraitDef.INSTANCE).equals(DrillDistributionTrait.SINGLETON)
        && (join.getJoinType() == JoinRelType.INNER || join.getJoinType() == JoinRelType.LEFT)
        ) {
      return true;
    }
    return false;
  }
 
Example 5
Source File: TestSamzaSqlLocalTableJoinFunction.java    From samza with Apache License 2.0 5 votes vote down vote up
@Test
public void testNullRecordWithLeftOuterJoin() {
  SamzaSqlRelMessage streamMsg = new SamzaSqlRelMessage(streamFieldNames, streamFieldValues,
      new SamzaSqlRelMsgMetadata(0L, 0L));
  JoinRelType joinRelType = JoinRelType.LEFT;
  List<Integer> streamKeyIds = Arrays.asList(0, 1);
  List<Integer> tableKeyIds = Arrays.asList(2, 3);

  JoinInputNode mockTableInputNode = mock(JoinInputNode.class);
  when(mockTableInputNode.getKeyIds()).thenReturn(tableKeyIds);
  when(mockTableInputNode.isPosOnRight()).thenReturn(true);
  when(mockTableInputNode.getFieldNames()).thenReturn(tableFieldNames);

  JoinInputNode mockStreamInputNode = mock(JoinInputNode.class);
  when(mockStreamInputNode.getKeyIds()).thenReturn(streamKeyIds);
  when(mockStreamInputNode.isPosOnRight()).thenReturn(false);
  when(mockStreamInputNode.getFieldNames()).thenReturn(streamFieldNames);

  SamzaSqlLocalTableJoinFunction joinFn =
      new SamzaSqlLocalTableJoinFunction(mockStreamInputNode, mockTableInputNode, joinRelType);
  SamzaSqlRelMessage outMsg = joinFn.apply(streamMsg, null);

  Assert.assertEquals(outMsg.getSamzaSqlRelRecord().getFieldValues().size(),
      outMsg.getSamzaSqlRelRecord().getFieldNames().size());
  List<String> expectedFieldNames = new ArrayList<>(streamFieldNames);
  expectedFieldNames.addAll(tableFieldNames);
  List<Object> expectedFieldValues = new ArrayList<>(streamFieldValues);
  expectedFieldValues.addAll(tableFieldNames.stream().map(name -> null).collect(Collectors.toList()));
  Assert.assertEquals(outMsg.getSamzaSqlRelRecord().getFieldValues(), expectedFieldValues);
}
 
Example 6
Source File: VectorizedHashJoinOperator.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@Override
public void noMoreToConsumeRight() throws Exception {
  state.is(State.CAN_CONSUME_R);

  if ((table.size() == 0) && !(joinType == JoinRelType.LEFT || joinType == JoinRelType.FULL)) {
    // nothing needs to be read on the left side as right side is empty
    state = State.DONE;
    return;
  }

  this.probe = new VectorizedProbe();
  this.probe.setup(
      context.getAllocator(),
      hyperContainer,
      left,
      probeOutputs,
      buildOutputs,
      probeIncomingKeys,
      buildOutputKeys,
      mode,
      config.getJoinType(),
      buildInfoList,
      startIndices,
      keyMatchBitVectors,
      maxHashTableIndex,
      table,
      probePivot,
      buildUnpivot,
      context.getTargetBatchSize(),
      comparator);
  state = State.CAN_CONSUME_L;
}
 
Example 7
Source File: FlinkJoinToMultiJoinRule.java    From flink with Apache License 2.0 5 votes vote down vote up
/**
 * Combines the join filters from the left and right inputs (if they are
 * MultiJoinRels) with the join filter in the joinrel into a single AND'd
 * join filter, unless the inputs correspond to null generating inputs in an
 * outer join.
 *
 * @param joinRel join rel
 * @param left    left child of the join
 * @param right   right child of the join
 * @return combined join filters AND-ed together
 */
private List<RexNode> combineJoinFilters(
		Join joinRel,
		RelNode left,
		RelNode right) {
	JoinRelType joinType = joinRel.getJoinType();

	// AND the join condition if this isn't a left or right outer join;
	// in those cases, the outer join condition is already tracked
	// separately
	final List<RexNode> filters = new ArrayList<>();
	if ((joinType != JoinRelType.LEFT) && (joinType != JoinRelType.RIGHT)) {
		filters.add(joinRel.getCondition());
	}
	if (canCombine(left, joinType.generatesNullsOnLeft())) {
		filters.add(((MultiJoin) left).getJoinFilter());
	}
	// Need to adjust the RexInputs of the right child, since
	// those need to shift over to the right
	if (canCombine(right, joinType.generatesNullsOnRight())) {
		MultiJoin multiJoin = (MultiJoin) right;
		filters.add(
				shiftRightFilter(joinRel, left, multiJoin,
						multiJoin.getJoinFilter()));
	}

	return filters;
}
 
Example 8
Source File: QueryOperationConverter.java    From flink with Apache License 2.0 5 votes vote down vote up
private JoinRelType convertJoinType(JoinType joinType) {
	switch (joinType) {
		case INNER:
			return JoinRelType.INNER;
		case LEFT_OUTER:
			return JoinRelType.LEFT;
		case RIGHT_OUTER:
			return JoinRelType.RIGHT;
		case FULL_OUTER:
			return JoinRelType.FULL;
		default:
			throw new TableException("Unknown join type: " + joinType);
	}
}
 
Example 9
Source File: JoinToMultiJoinRule.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Combines the join filters from the left and right inputs (if they are
 * MultiJoinRels) with the join filter in the joinrel into a single AND'd
 * join filter, unless the inputs correspond to null generating inputs in an
 * outer join
 *
 * @param joinRel join rel
 * @param left    left child of the join
 * @param right   right child of the join
 * @return combined join filters AND-ed together
 */
private List<RexNode> combineJoinFilters(
    Join joinRel,
    RelNode left,
    RelNode right) {
  JoinRelType joinType = joinRel.getJoinType();

  // AND the join condition if this isn't a left or right outer join;
  // in those cases, the outer join condition is already tracked
  // separately
  final List<RexNode> filters = new ArrayList<>();
  if ((joinType != JoinRelType.LEFT) && (joinType != JoinRelType.RIGHT)) {
    filters.add(joinRel.getCondition());
  }
  if (canCombine(left, joinType.generatesNullsOnLeft())) {
    filters.add(((MultiJoin) left).getJoinFilter());
  }
  // Need to adjust the RexInputs of the right child, since
  // those need to shift over to the right
  if (canCombine(right, joinType.generatesNullsOnRight())) {
    MultiJoin multiJoin = (MultiJoin) right;
    filters.add(
        shiftRightFilter(joinRel, left, multiJoin,
            multiJoin.getJoinFilter()));
  }

  return filters;
}
 
Example 10
Source File: JoinStatus.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Return state of join based on status of left and right iterator.
 * @return
 *  1. JoinOutcome.NO_MORE_DATA : Join is finished
 *  2. JoinOutcome.FAILURE : There is an error during join.
 *  3. JoinOutcome.BATCH_RETURNED : one of the side has data
 *  4. JoinOutcome.SCHEMA_CHANGED : one of the side has change in schema.
 */
public JoinOutcome getOutcome() {
  // on STOP, OUT_OF_MEMORY return FAILURE.
  if (!ok || eitherMatches(IterOutcome.STOP)) {
    return JoinOutcome.FAILURE;
  }
  if (hasMoreData) {
    return JoinOutcome.BATCH_RETURNED;
  }
  if (bothMatches(IterOutcome.NONE) ||
    (joinType == JoinRelType.INNER && eitherMatches(IterOutcome.NONE)) ||
    (joinType == JoinRelType.LEFT && getLeftStatus() == IterOutcome.NONE) ||
    (joinType == JoinRelType.RIGHT && getRightStatus() == IterOutcome.NONE)) {
    return JoinOutcome.NO_MORE_DATA;
  }
  if (bothMatches(IterOutcome.OK) ||
    (eitherMatches(IterOutcome.NONE) && eitherMatches(IterOutcome.OK))) {
    return JoinOutcome.BATCH_RETURNED;
  }
  if (eitherMatches(IterOutcome.OK_NEW_SCHEMA)) {
    return JoinOutcome.SCHEMA_CHANGED;
  }
  // should never see NOT_YET
  if (eitherMatches(IterOutcome.NOT_YET)) {
    return JoinOutcome.WAITING;
  }
  ok = false;

  return JoinOutcome.FAILURE;
}
 
Example 11
Source File: MergeJoinComparatorTemplate.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
/**
 * while (r < s) { advance r, yield <r, null> if left or full join }
 * while (r > s) { advance s, yield <null, s> if right or full join }
 *
 * if (r == s) {
 *   mark s
 *   yield <r, s>
 *   advance s
 *
 *   goto inner_loop
 * }
 *
 */
private void continueFromOutOfLoops() {
  while (outputRecordsCounter < targetRecordsPerBatch) {
    if (!leftIterator.hasNext() || !rightIterator.hasNext()) {
      // need more data
      return;
    }

    final Pair<VectorAccessible, Integer> left = leftIterator.peek();
    final Pair<VectorAccessible, Integer> right = rightIterator.peek();

    final int compareOutput = _doCompare(left.getLeft(), right.getLeft(), left.getRight(), right.getRight());

    if (compareOutput < 0) {
      // left < right
      if (joinType == JoinRelType.LEFT || joinType == JoinRelType.FULL) {
        yieldLeft(left.getLeft(), left.getRight());
      }
      leftIterator.next();
    } else if (compareOutput > 0) {
      // left > right
      if (joinType == JoinRelType.RIGHT || joinType == JoinRelType.FULL) {
        yieldRight(right.getLeft(), right.getRight());
      }
      rightIterator.next();
    } else {
      // equal
      yield(left.getLeft(), right.getLeft(), left.getRight(), right.getRight());

      rightIterator.mark();
      rightIterator.next();

      state = InternalState.IN_INNER_LOOP;
      return;
    }
  }
}
 
Example 12
Source File: QueryOperationConverter.java    From flink with Apache License 2.0 5 votes vote down vote up
private JoinRelType convertJoinType(JoinType joinType) {
	switch (joinType) {
		case INNER:
			return JoinRelType.INNER;
		case LEFT_OUTER:
			return JoinRelType.LEFT;
		case RIGHT_OUTER:
			return JoinRelType.RIGHT;
		case FULL_OUTER:
			return JoinRelType.FULL;
		default:
			throw new TableException("Unknown join type: " + joinType);
	}
}
 
Example 13
Source File: QueryOperationConverter.java    From flink with Apache License 2.0 5 votes vote down vote up
private JoinRelType convertJoinType(JoinType joinType) {
	switch (joinType) {
		case INNER:
			return JoinRelType.INNER;
		case LEFT_OUTER:
			return JoinRelType.LEFT;
		case RIGHT_OUTER:
			return JoinRelType.RIGHT;
		case FULL_OUTER:
			return JoinRelType.FULL;
		default:
			throw new TableException("Unknown join type: " + joinType);
	}
}
 
Example 14
Source File: JoinTemplate.java    From Bats with Apache License 2.0 4 votes vote down vote up
/**
 * Copy rows from the input record batches until the output record batch is full
 * @param status  State of the join operation (persists across multiple record batches/schema changes)
 * @return  true of join succeeded; false if the worker needs to be regenerated
 */
public final boolean doJoin(final JoinStatus status) {
  final boolean isLeftJoin = (((MergeJoinPOP)status.outputBatch.getPopConfig()).getJoinType() == JoinRelType.LEFT);
  status.setHasMoreData(false);
  while (!status.isOutgoingBatchFull()) {
    if (status.right.finished()) {
      if (isLeftJoin) {
        while (!status.left.finished()) {
          if (status.isOutgoingBatchFull()) {
            status.setHasMoreData(true);
            return true;
          }
          doCopyLeft(status.left.getCurrentPosition(), status.getOutPosition());
          status.incOutputPos();
          status.left.next();
        }
      }
      return true;
    }
    if (status.left.finished()) {
      return true;
    }
    final int comparison = Integer.signum(doCompare(status.left.getCurrentPosition(), status.right.getCurrentPosition()));
    switch (comparison) {
      case -1:
        // left key < right key
        if (isLeftJoin) {
          doCopyLeft(status.left.getCurrentPosition(), status.getOutPosition());
          status.incOutputPos();
        }
        status.left.next();
        continue;

      case 0:
        // left key == right key
        // Mark current position in right iterator.
        // If we have set a mark in previous iteration but didn't finish the inner loop,
        // skip current right side as its already copied in earlier iteration.
        if (status.shouldMark()) {
          status.right.mark();
          // Copy all equal keys from right side to the output record batch.
          doCopyLeft(status.left.getCurrentPosition(), status.getOutPosition());
          doCopyRight(status.right.getCurrentPosition(), status.getOutPosition());
          status.incOutputPos();
        }
        if (status.isOutgoingBatchFull()) {
          // Leave iterators at their current positions and markers.
          // Don't mark on all subsequent doJoin iterations.
          status.setHasMoreData(true);
          status.disableMarking();
          return true;
        }
        // Move to next position in right iterator.
        status.right.next();
        while (!status.right.finished()) {
          if (doCompare(status.left.getCurrentPosition(), status.right.getCurrentPosition()) == 0) {
            doCopyLeft(status.left.getCurrentPosition(), status.getOutPosition());
            doCopyRight(status.right.getCurrentPosition(), status.getOutPosition());
            status.incOutputPos();
            if (status.isOutgoingBatchFull()) {
              status.setHasMoreData(true);
              status.disableMarking();
              return true;
            }
            status.right.next();
          } else {
            break;
          }
        }
        status.right.reset();
        // Enable marking only when we have consumed all equal keys on right side.
        status.enableMarking();
        status.left.next();
        continue;
      case 1:
        // left key > right key
        status.right.next();
        continue;

      default:
        throw new IllegalStateException();
    }
  }
  return true;
}
 
Example 15
Source File: OLAPJoinRel.java    From kylin-on-parquet-v2 with Apache License 2.0 4 votes vote down vote up
@Override
    public void implementOLAP(OLAPImplementor implementor) {

        // create context for root join
        if (!(implementor.getParentNode() instanceof OLAPJoinRel) && !isParentMerelyPermutation(implementor)) {
            implementor.allocateContext();
        }
        //parent context
        this.context = implementor.getContext();
        this.context.allOlapJoins.add(this);
        this.isTopJoin = !this.context.hasJoin;
        this.context.hasJoin = true;

        boolean leftHasSubquery = false;
        boolean rightHasSubquery = false;

        // as we keep the first table as fact table, we need to visit from left to right
        implementor.fixSharedOlapTableScanOnTheLeft(this);
        implementor.visitChild(this.left, this);

        //current  has another context
        if (this.context != implementor.getContext() || ((OLAPRel) this.left).hasSubQuery()) {
            this.hasSubQuery = true;
            leftHasSubquery = true;
            // if child is also an OLAPJoin, then the context has already been popped
            if (this.context != implementor.getContext()) {
                implementor.freeContext();
            }
        }

        if (leftHasSubquery) {
            // After KYLIN-2579, leftHasSubquery means right side have to be separate olap context 
            implementor.setNewOLAPContextRequired(true);
        }

        implementor.fixSharedOlapTableScanOnTheRight(this);
        implementor.visitChild(this.right, this);
        if (this.context != implementor.getContext() || ((OLAPRel) this.right).hasSubQuery()) {
            this.hasSubQuery = true;
            rightHasSubquery = true;
            // if child is also an OLAPJoin, then the context has already been popped

            if (leftHasSubquery) {
                Preconditions.checkState(!implementor.isNewOLAPContextRequired());//should have been satisfied
                Preconditions.checkState(this.context != implementor.getContext(), "missing a new olapcontext");
            }

            if (this.context != implementor.getContext()) {
                implementor.freeContext();
            }
        }

        this.columnRowType = buildColumnRowType();

        if (isTopJoin) {
            this.context.afterJoin = true;
        }

        if (!this.hasSubQuery) {
//            this.context.allColumns.clear();

            // build JoinDesc
            Preconditions.checkState(this.getCondition() instanceof RexCall, "Cartesian Join is not supported.");

            RexCall condition = (RexCall) this.getCondition();
            JoinDesc join = buildJoin(condition);

            JoinRelType joinRelType = this.getJoinType();
            String joinType = joinRelType == JoinRelType.INNER ? "INNER"
                    : joinRelType == JoinRelType.LEFT ? "LEFT" : joinRelType == JoinRelType.RIGHT ? "RIGHT" : "FULL";
            join.setType(joinType);

            this.context.joins.add(join);
        } else {
            //When join contains subquery, the join-condition fields of fact_table will add into context.
            Multimap<TblColRef, TblColRef> joinCol = HashMultimap.create();
            translateJoinColumn(this.getCondition(), joinCol);

            for (Map.Entry<TblColRef, TblColRef> columnPair : joinCol.entries()) {
                TblColRef fromCol = (rightHasSubquery ? columnPair.getKey() : columnPair.getValue());
                this.context.subqueryJoinParticipants.add(fromCol);
            }
            joinCol.clear();
        }
    }
 
Example 16
Source File: RelDecorrelator.java    From flink with Apache License 2.0 4 votes vote down vote up
private void onMatch2(
    RelOptRuleCall call,
    LogicalCorrelate correlate,
    RelNode leftInput,
    LogicalProject aggOutputProject,
    LogicalAggregate aggregate) {
  if (generatedCorRels.contains(correlate)) {
    // This Correlate was generated by a previous invocation of
    // this rule. No further work to do.
    return;
  }

  setCurrent(call.getPlanner().getRoot(), correlate);

  // check for this pattern
  // The pattern matching could be simplified if rules can be applied
  // during decorrelation,
  //
  // CorrelateRel(left correlation, condition = true)
  //   leftInput
  //   Project-A (a RexNode)
  //     Aggregate (groupby (0), agg0(), agg1()...)

  // check aggOutputProj projects only one expression
  List<RexNode> aggOutputProjExprs = aggOutputProject.getProjects();
  if (aggOutputProjExprs.size() != 1) {
    return;
  }

  JoinRelType joinType = correlate.getJoinType();
  // corRel.getCondition was here, however Correlate was updated so it
  // never includes a join condition. The code was not modified for brevity.
  RexNode joinCond = relBuilder.literal(true);
  if ((joinType != JoinRelType.LEFT)
      || (joinCond != relBuilder.literal(true))) {
    return;
  }

  // check that the agg is on the entire input
  if (!aggregate.getGroupSet().isEmpty()) {
    return;
  }

  List<AggregateCall> aggCalls = aggregate.getAggCallList();
  Set<Integer> isCount = new HashSet<>();

  // remember the count() positions
  int i = -1;
  for (AggregateCall aggCall : aggCalls) {
    ++i;
    if (aggCall.getAggregation() instanceof SqlCountAggFunction) {
      isCount.add(i);
    }
  }

  // now rewrite the plan to
  //
  // Project-A' (all LHS plus transformed original projections,
  //             replacing references to count() with case statement)
  //   Correlate(left correlation, condition = true)
  //     leftInput
  //     Aggregate(groupby (0), agg0(), agg1()...)
  //
  LogicalCorrelate newCorrelate =
      LogicalCorrelate.create(leftInput, aggregate,
          correlate.getCorrelationId(), correlate.getRequiredColumns(),
          correlate.getJoinType());

  // remember this rel so we don't fire rule on it again
  // REVIEW jhyde 29-Oct-2007: rules should not save state; rule
  // should recognize patterns where it does or does not need to do
  // work
  generatedCorRels.add(newCorrelate);

  // need to update the mapCorToCorRel Update the output position
  // for the corVars: only pass on the corVars that are not used in
  // the join key.
  if (cm.mapCorToCorRel.get(correlate.getCorrelationId()) == correlate) {
    cm.mapCorToCorRel.put(correlate.getCorrelationId(), newCorrelate);
  }

  RelNode newOutput =
      aggregateCorrelatorOutput(newCorrelate, aggOutputProject, isCount);

  call.transformTo(newOutput);
}
 
Example 17
Source File: LateralJoinBatch.java    From Bats with Apache License 2.0 4 votes vote down vote up
/**
 * Main entry point for producing the output records. This method populates the output batch after cross join of
 * the record in a given left batch at left index and all the corresponding rows in right batches produced by Unnest
 * for current left batch. For each call to this function number of records copied in output batch is limited to
 * maximum rows output batch can hold or the number of rows in right incoming batch
 */
private void crossJoinAndOutputRecords() {
  final int rightRecordCount = right.getRecordCount();

  // If there is no record in right batch just return current index in output batch
  if (rightRecordCount <= 0) {
    return;
  }

  // Check if right batch is empty since we have to handle left join case
  Preconditions.checkState(rightJoinIndex != -1, "Right batch record count is >0 but index is -1");

  int currentOutIndex = outputIndex;
  // Number of rows that can be copied in output batch
  int maxAvailableRowSlot = maxOutputRowCount - currentOutIndex;

  if (logger.isDebugEnabled()) {
    logger.debug("Producing output for leftIndex: {}, rightIndex: {}, rightRecordCount: {}, outputIndex: {} and " +
      "availableSlotInOutput: {}", leftJoinIndex, rightJoinIndex, rightRecordCount, outputIndex, maxAvailableRowSlot);
    logger.debug("Output Batch stats before copying new data: {}", new RecordBatchSizer(this));
  }

  // Assuming that first vector in right batch is for implicitColumn.
  // get a mapping of number of rows for each rowId present in current right side batch
  //final Map<Integer, Integer> indexToFreq = getRowIdToRowCountMapping();
  final IntVector rowIdVector = (IntVector) implicitVector;
  final int leftRecordCount = left.getRecordCount();

  // we need to have both conditions because in left join case we can exceed the maxAvailableRowSlot before reaching
  // rightBatch end or vice-versa
  while(maxAvailableRowSlot > 0 && rightJoinIndex < rightRecordCount) {
    // Get rowId from current right row
    int currentRowId = rowIdVector.getAccessor().get(rightJoinIndex);
    int leftRowId = leftJoinIndex + 1;
    int numRowsCopied = 0;

    if (currentRowId > leftRecordCount || leftJoinIndex > leftRecordCount) {
      // Not using Preconditions.checkState here since along with condition evaluation there will be cost of boxing
      // the arguments.
      throw new IllegalStateException(String.format("Either RowId in right batch is greater than total records in " +
        "left batch or all rows in left batch is processed but there are still rows in right batch. " +
        "Details[RightRowId: %s, LeftRecordCount: %s, LeftJoinIndex: %s, RightJoinIndex: %s]",
        currentRowId, leftRecordCount, leftJoinIndex, rightJoinIndex));
    }

    if (logger.isTraceEnabled()) {
      // Inside the if condition to eliminate parameter boxing cost
      logger.trace("leftRowId and currentRowId are: {}, {}", leftRowId, currentRowId);
    }

    // If leftRowId matches the rowId in right row then emit left and right row. Increment outputIndex, rightJoinIndex
    // and numRowsCopied. Also set leftMatchFound to true to indicate when to increase leftJoinIndex.
    if (leftRowId == currentRowId) {
      // there is a match
      matchedRecordFound = true;
      numRowsCopied = 1;
      //numRowsCopied = Math.min(indexToFreq.get(currentRowId), maxAvailableRowSlot);
      emitRight(rightJoinIndex, outputIndex, numRowsCopied);
      emitLeft(leftJoinIndex, outputIndex, numRowsCopied);
      outputIndex += numRowsCopied;
      rightJoinIndex += numRowsCopied;
    } else if (leftRowId < currentRowId) {
      // If a matching record for leftRowId was found in right batch in previous iteration, increase the leftJoinIndex
      // and reset the matchedRecordFound flag
      if (matchedRecordFound) {
        matchedRecordFound = false;
        ++leftJoinIndex;
        continue;
      } else { // If no matching row was found in right batch then in case of left join produce left row in output
        // and increase the indexes properly to reflect that
        if (JoinRelType.LEFT == popConfig.getJoinType()) {
          numRowsCopied = 1;
          emitLeft(leftJoinIndex, outputIndex, numRowsCopied);
          ++outputIndex;
        }
        ++leftJoinIndex;
      }
    } else {
      Preconditions.checkState(leftRowId <= currentRowId, "Unexpected case where rowId " +
        "%s in right batch of lateral is smaller than rowId %s in left batch being processed",
        currentRowId, leftRowId);
    }
    // Update the max available rows slot in output batch
    maxAvailableRowSlot -= numRowsCopied;
  }
}
 
Example 18
Source File: RelDecorrelator.java    From calcite with Apache License 2.0 4 votes vote down vote up
private void onMatch2(
    RelOptRuleCall call,
    Correlate correlate,
    RelNode leftInput,
    Project aggOutputProject,
    Aggregate aggregate) {
  if (generatedCorRels.contains(correlate)) {
    // This Correlate was generated by a previous invocation of
    // this rule. No further work to do.
    return;
  }

  setCurrent(call.getPlanner().getRoot(), correlate);

  // check for this pattern
  // The pattern matching could be simplified if rules can be applied
  // during decorrelation,
  //
  // CorrelateRel(left correlation, condition = true)
  //   leftInput
  //   Project-A (a RexNode)
  //     Aggregate (groupby (0), agg0(), agg1()...)

  // check aggOutputProj projects only one expression
  List<RexNode> aggOutputProjExprs = aggOutputProject.getProjects();
  if (aggOutputProjExprs.size() != 1) {
    return;
  }

  JoinRelType joinType = correlate.getJoinType();
  // corRel.getCondition was here, however Correlate was updated so it
  // never includes a join condition. The code was not modified for brevity.
  RexNode joinCond = relBuilder.literal(true);
  if ((joinType != JoinRelType.LEFT)
      || (joinCond != relBuilder.literal(true))) {
    return;
  }

  // check that the agg is on the entire input
  if (!aggregate.getGroupSet().isEmpty()) {
    return;
  }

  List<AggregateCall> aggCalls = aggregate.getAggCallList();
  Set<Integer> isCount = new HashSet<>();

  // remember the count() positions
  int i = -1;
  for (AggregateCall aggCall : aggCalls) {
    ++i;
    if (aggCall.getAggregation() instanceof SqlCountAggFunction) {
      isCount.add(i);
    }
  }

  // now rewrite the plan to
  //
  // Project-A' (all LHS plus transformed original projections,
  //             replacing references to count() with case statement)
  //   Correlate(left correlation, condition = true)
  //     leftInput
  //     Aggregate(groupby (0), agg0(), agg1()...)
  //
  List<RexNode> requiredNodes =
      correlate.getRequiredColumns().asList().stream()
          .map(ord -> relBuilder.getRexBuilder().makeInputRef(correlate, ord))
          .collect(Collectors.toList());
  Correlate newCorrelate = (Correlate) relBuilder.push(leftInput)
      .push(aggregate).correlate(correlate.getJoinType(),
          correlate.getCorrelationId(),
          requiredNodes).build();


  // remember this rel so we don't fire rule on it again
  // REVIEW jhyde 29-Oct-2007: rules should not save state; rule
  // should recognize patterns where it does or does not need to do
  // work
  generatedCorRels.add(newCorrelate);

  // need to update the mapCorToCorRel Update the output position
  // for the corVars: only pass on the corVars that are not used in
  // the join key.
  if (cm.mapCorToCorRel.get(correlate.getCorrelationId()) == correlate) {
    cm.mapCorToCorRel.put(correlate.getCorrelationId(), newCorrelate);
  }

  RelNode newOutput =
      aggregateCorrelatorOutput(newCorrelate, aggOutputProject, isCount);

  call.transformTo(newOutput);
}
 
Example 19
Source File: SortJoinTransposeRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
@Override public void onMatch(RelOptRuleCall call) {
  final Sort sort = call.rel(0);
  final Join join = call.rel(1);

  // We create a new sort operator on the corresponding input
  final RelNode newLeftInput;
  final RelNode newRightInput;
  final RelMetadataQuery mq = call.getMetadataQuery();
  if (join.getJoinType() == JoinRelType.LEFT) {
    // If the input is already sorted and we are not reducing the number of tuples,
    // we bail out
    if (RelMdUtil.checkInputForCollationAndLimit(mq, join.getLeft(),
        sort.getCollation(), sort.offset, sort.fetch)) {
      return;
    }
    newLeftInput = sort.copy(sort.getTraitSet(), join.getLeft(), sort.getCollation(),
        sort.offset, sort.fetch);
    newRightInput = join.getRight();
  } else {
    final RelCollation rightCollation =
        RelCollationTraitDef.INSTANCE.canonize(
            RelCollations.shift(sort.getCollation(),
                -join.getLeft().getRowType().getFieldCount()));
    // If the input is already sorted and we are not reducing the number of tuples,
    // we bail out
    if (RelMdUtil.checkInputForCollationAndLimit(mq, join.getRight(),
        rightCollation, sort.offset, sort.fetch)) {
      return;
    }
    newLeftInput = join.getLeft();
    newRightInput = sort.copy(sort.getTraitSet().replace(rightCollation),
        join.getRight(), rightCollation, sort.offset, sort.fetch);
  }
  // We copy the join and the top sort operator
  final RelNode joinCopy = join.copy(join.getTraitSet(), join.getCondition(), newLeftInput,
      newRightInput, join.getJoinType(), join.isSemiJoinDone());
  final RelNode sortCopy = sort.copy(sort.getTraitSet(), joinCopy, sort.getCollation(),
      sort.offset, sort.fetch);

  call.transformTo(sortCopy);
}
 
Example 20
Source File: SortJoinTransposeRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
@Override public void onMatch(RelOptRuleCall call) {
  final Sort sort = call.rel(0);
  final Join join = call.rel(1);

  // We create a new sort operator on the corresponding input
  final RelNode newLeftInput;
  final RelNode newRightInput;
  final RelMetadataQuery mq = call.getMetadataQuery();
  if (join.getJoinType() == JoinRelType.LEFT) {
    // If the input is already sorted and we are not reducing the number of tuples,
    // we bail out
    if (RelMdUtil.checkInputForCollationAndLimit(mq, join.getLeft(),
        sort.getCollation(), sort.offset, sort.fetch)) {
      return;
    }
    newLeftInput = sort.copy(sort.getTraitSet(), join.getLeft(), sort.getCollation(),
        sort.offset, sort.fetch);
    newRightInput = join.getRight();
  } else {
    final RelCollation rightCollation =
        RelCollationTraitDef.INSTANCE.canonize(
            RelCollations.shift(sort.getCollation(),
                -join.getLeft().getRowType().getFieldCount()));
    // If the input is already sorted and we are not reducing the number of tuples,
    // we bail out
    if (RelMdUtil.checkInputForCollationAndLimit(mq, join.getRight(),
        rightCollation, sort.offset, sort.fetch)) {
      return;
    }
    newLeftInput = join.getLeft();
    newRightInput = sort.copy(sort.getTraitSet().replace(rightCollation),
        join.getRight(), rightCollation, sort.offset, sort.fetch);
  }
  // We copy the join and the top sort operator
  final RelNode joinCopy = join.copy(join.getTraitSet(), join.getCondition(), newLeftInput,
      newRightInput, join.getJoinType(), join.isSemiJoinDone());
  final RelNode sortCopy = sort.copy(sort.getTraitSet(), joinCopy, sort.getCollation(),
      sort.offset, sort.fetch);

  call.transformTo(sortCopy);
}