Java Code Examples for org.apache.calcite.rel.core.JoinRelType#FULL
The following examples show how to use
org.apache.calcite.rel.core.JoinRelType#FULL .
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: MergeJoinPrel.java From Bats with Apache License 2.0 | 6 votes |
@Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) { if (PrelUtil.getSettings(getCluster()).useDefaultCosting()) { return super.computeSelfCost(planner, mq).multiplyBy(.1); } if (joincategory == JoinCategory.CARTESIAN || joincategory == JoinCategory.INEQUALITY || getJoinType() == JoinRelType.FULL) { return planner.getCostFactory().makeInfiniteCost(); } double leftRowCount = mq.getRowCount(this.getLeft()); double rightRowCount = mq.getRowCount(this.getRight()); // cost of evaluating each leftkey=rightkey join condition double joinConditionCost = DrillCostBase.COMPARE_CPU_COST * this.getLeftKeys().size(); double cpuCost = joinConditionCost * (leftRowCount + rightRowCount); DrillCostFactory costFactory = (DrillCostFactory) planner.getCostFactory(); return costFactory.makeCost(leftRowCount + rightRowCount, cpuCost, 0, 0); }
Example 2
Source File: HBTQueryConvertor.java From Mycat2 with GNU General Public License v3.0 | 6 votes |
private JoinRelType joinOp(HBTOp op) { switch (op) { case INNER_JOIN: return JoinRelType.INNER; case LEFT_JOIN: return JoinRelType.LEFT; case RIGHT_JOIN: return JoinRelType.RIGHT; case FULL_JOIN: return JoinRelType.FULL; case SEMI_JOIN: return JoinRelType.SEMI; case ANTI_JOIN: return JoinRelType.ANTI; case CORRELATE_INNER_JOIN: return JoinRelType.INNER; case CORRELATE_LEFT_JOIN: return JoinRelType.LEFT; default: throw new UnsupportedOperationException(); } }
Example 3
Source File: MergeJoinComparatorTemplate.java From dremio-oss with Apache License 2.0 | 6 votes |
@Override public boolean finishNonMatching() { Preconditions.checkArgument(!leftIterator.hasNext() || !rightIterator.hasNext()); // allocate new buffer for new batch if (outputRecordsCounter == 0) { outgoing.allocateNew(); } if (joinType == JoinRelType.RIGHT) { return projectRightNonMatching(); } else if (joinType == JoinRelType.LEFT) { return projectLeftNonMatching(); } else if (joinType == JoinRelType.FULL) { if (leftIterator.hasNext()) { return projectLeftNonMatching(); } else { return projectRightNonMatching(); } } else { throw new IllegalStateException("Reach unexpected state"); } }
Example 4
Source File: EnumerableTraitsUtils.java From calcite with Apache License 2.0 | 6 votes |
/** * This function can be reused when a Join's traits pass-down shall only * pass through collation to left input. * * @param required required trait set for the join * @param joinType the join type * @param leftInputFieldCount number of field count of left join input * @param joinTraitSet trait set of the join */ static Pair<RelTraitSet, List<RelTraitSet>> passThroughTraitsForJoin( RelTraitSet required, JoinRelType joinType, int leftInputFieldCount, RelTraitSet joinTraitSet) { RelCollation collation = required.getCollation(); if (collation == null || collation == RelCollations.EMPTY || joinType == JoinRelType.FULL || joinType == JoinRelType.RIGHT) { return null; } for (RelFieldCollation fc : collation.getFieldCollations()) { // If field collation belongs to right input: cannot push down collation. if (fc.getFieldIndex() >= leftInputFieldCount) { return null; } } RelTraitSet passthroughTraitSet = joinTraitSet.replace(collation); return Pair.of(passthroughTraitSet, ImmutableList.of( passthroughTraitSet, passthroughTraitSet.replace(RelCollations.EMPTY))); }
Example 5
Source File: HashJoinProbeTemplate.java From Bats with Apache License 2.0 | 5 votes |
@Override public void changeToFinalProbeState() { // We are done with the (left) probe phase. // If it's a RIGHT or a FULL join then need to get the unmatched indexes from the build side probeState = (joinType == JoinRelType.RIGHT || joinType == JoinRelType.FULL) ? ProbeState.PROJECT_RIGHT : ProbeState.DONE; // else we're done }
Example 6
Source File: PigRelOpVisitor.java From calcite with Apache License 2.0 | 5 votes |
/** * 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 7
Source File: QueryOperationConverter.java From flink with Apache License 2.0 | 5 votes |
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 8
Source File: EnumerableHashJoin.java From calcite with Apache License 2.0 | 5 votes |
@Override public DeriveMode getDeriveMode() { if (joinType == JoinRelType.FULL || joinType == JoinRelType.RIGHT) { return DeriveMode.PROHIBITED; } return DeriveMode.LEFT_FIRST; }
Example 9
Source File: EnumerableBatchNestedLoopJoin.java From calcite with Apache License 2.0 | 5 votes |
@Override public DeriveMode getDeriveMode() { if (joinType == JoinRelType.FULL || joinType == JoinRelType.RIGHT) { return DeriveMode.PROHIBITED; } return DeriveMode.LEFT_FIRST; }
Example 10
Source File: VectorizedHashJoinOperator.java From dremio-oss with Apache License 2.0 | 5 votes |
@Override public void noMoreToConsumeLeft() throws Exception { state.is(State.CAN_CONSUME_L); finishedProbe = true; if(joinType == JoinRelType.FULL || joinType == JoinRelType.RIGHT){ // if we need to project build records that didn't match, make sure we do so. state = State.CAN_PRODUCE; } else { state = State.DONE; } }
Example 11
Source File: ApexRelNode.java From attic-apex-malhar with Apache License 2.0 | 5 votes |
@Override public RelInfo visit(RelContext context, RelNode node, List<RelInfo> inputStreams) { Join join = (Join)node; if (inputStreams.size() != 2) { throw new UnsupportedOperationException("Join is a BiRel"); } if ((join.getJoinType() == JoinRelType.FULL) || (join.getJoinType() == JoinRelType.LEFT) || (join.getJoinType() == JoinRelType.RIGHT)) { throw new UnsupportedOperationException("Outer joins are not supported"); } final List<Integer> leftKeys = new ArrayList<>(); final List<Integer> rightKeys = new ArrayList<>(); RexNode remaining = RelOptUtil.splitJoinCondition(join.getLeft(), join.getRight(), join.getCondition(), leftKeys, rightKeys); if (leftKeys.size() != rightKeys.size()) { throw new RuntimeException("Unexpected condition reached. Left and right condition count should be same"); } if (leftKeys.size() == 0) { throw new UnsupportedOperationException("Theta joins are not supported."); } RelInfo relInfo = addInnerJoinOperator(join, leftKeys, rightKeys, context); if (!remaining.isAlwaysTrue()) { relInfo = addJoinFilter(join, remaining, relInfo, context); } return relInfo; }
Example 12
Source File: HashJoinOperator.java From dremio-oss with Apache License 2.0 | 5 votes |
@Override public void noMoreToConsumeRight() throws Exception { state.is(State.CAN_CONSUME_R); if (hashTable.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.hashJoinProbe = setupHashJoinProbe(); state = State.CAN_CONSUME_L; }
Example 13
Source File: HashJoinOperator.java From dremio-oss with Apache License 2.0 | 5 votes |
@Override public void noMoreToConsumeLeft() throws Exception { state.is(State.CAN_CONSUME_L); finishedProbe = true; if(joinType == JoinRelType.FULL || joinType == JoinRelType.RIGHT){ // if we need to project build records that didn't match, make sure we do so. state = State.CAN_PRODUCE; } else { state = State.DONE; } }
Example 14
Source File: RelMdColumnUniqueness.java From calcite with Apache License 2.0 | 4 votes |
public Boolean areColumnsUnique(Join rel, RelMetadataQuery mq, ImmutableBitSet columns, boolean ignoreNulls) { columns = decorateWithConstantColumnsFromPredicates(columns, rel, mq); if (columns.cardinality() == 0) { return false; } final RelNode left = rel.getLeft(); final RelNode right = rel.getRight(); // Semi or anti join should ignore uniqueness of the right input. if (!rel.getJoinType().projectsRight()) { return mq.areColumnsUnique(left, columns, ignoreNulls); } // Divide up the input column mask into column masks for the left and // right sides of the join final Pair<ImmutableBitSet, ImmutableBitSet> leftAndRightColumns = splitLeftAndRightColumns(rel.getLeft().getRowType().getFieldCount(), columns); final ImmutableBitSet leftColumns = leftAndRightColumns.left; final ImmutableBitSet rightColumns = leftAndRightColumns.right; // for FULL OUTER JOIN if columns contain column from both inputs it is not // guaranteed that the result will be unique if (!ignoreNulls && rel.getJoinType() == JoinRelType.FULL && leftColumns.cardinality() > 0 && rightColumns.cardinality() > 0) { return false; } // If the original column mask contains columns from both the left and // right hand side, then the columns are unique if and only if they're // unique for their respective join inputs Boolean leftUnique = mq.areColumnsUnique(left, leftColumns, ignoreNulls); Boolean rightUnique = mq.areColumnsUnique(right, rightColumns, ignoreNulls); if ((leftColumns.cardinality() > 0) && (rightColumns.cardinality() > 0)) { if ((leftUnique == null) || (rightUnique == null)) { return null; } else { return leftUnique && rightUnique; } } // If we're only trying to determine uniqueness for columns that // originate from one join input, then determine if the equijoin // columns from the other join input are unique. If they are, then // the columns are unique for the entire join if they're unique for // the corresponding join input, provided that input is not null // generating. final JoinInfo joinInfo = rel.analyzeCondition(); if (leftColumns.cardinality() > 0) { if (rel.getJoinType().generatesNullsOnLeft()) { return false; } Boolean rightJoinColsUnique = mq.areColumnsUnique(right, joinInfo.rightSet(), ignoreNulls); if ((rightJoinColsUnique == null) || (leftUnique == null)) { return null; } return rightJoinColsUnique && leftUnique; } else if (rightColumns.cardinality() > 0) { if (rel.getJoinType().generatesNullsOnRight()) { return false; } Boolean leftJoinColsUnique = mq.areColumnsUnique(left, joinInfo.leftSet(), ignoreNulls); if ((leftJoinColsUnique == null) || (rightUnique == null)) { return null; } return leftJoinColsUnique && rightUnique; } throw new AssertionError(); }
Example 15
Source File: JoinToMultiJoinRule.java From Bats with Apache License 2.0 | 4 votes |
public void onMatch(RelOptRuleCall call) { final Join origJoin = call.rel(0); final RelNode left = call.rel(1); final RelNode right = call.rel(2); // combine the children MultiJoin inputs into an array of inputs // for the new MultiJoin final List<ImmutableBitSet> projFieldsList = new ArrayList<>(); final List<int[]> joinFieldRefCountsList = new ArrayList<>(); final List<RelNode> newInputs = combineInputs( origJoin, left, right, projFieldsList, joinFieldRefCountsList); // combine the outer join information from the left and right // inputs, and include the outer join information from the current // join, if it's a left/right outer join final List<Pair<JoinRelType, RexNode>> joinSpecs = new ArrayList<>(); combineOuterJoins( origJoin, newInputs, left, right, joinSpecs); // pull up the join filters from the children MultiJoinRels and // combine them with the join filter associated with this LogicalJoin to // form the join filter for the new MultiJoin List<RexNode> newJoinFilters = combineJoinFilters(origJoin, left, right); // add on the join field reference counts for the join condition // associated with this LogicalJoin final ImmutableMap<Integer, ImmutableIntList> newJoinFieldRefCountsMap = addOnJoinFieldRefCounts(newInputs, origJoin.getRowType().getFieldCount(), origJoin.getCondition(), joinFieldRefCountsList); List<RexNode> newPostJoinFilters = combinePostJoinFilters(origJoin, left, right); final RexBuilder rexBuilder = origJoin.getCluster().getRexBuilder(); RelNode multiJoin = new MultiJoin( origJoin.getCluster(), newInputs, RexUtil.composeConjunction(rexBuilder, newJoinFilters), origJoin.getRowType(), origJoin.getJoinType() == JoinRelType.FULL, Pair.right(joinSpecs), Pair.left(joinSpecs), projFieldsList, newJoinFieldRefCountsMap, RexUtil.composeConjunction(rexBuilder, newPostJoinFilters, true)); call.transformTo(multiJoin); }
Example 16
Source File: HashJoinProbeTemplate.java From dremio-oss with Apache License 2.0 | 4 votes |
@Override public void setupHashJoinProbe( FunctionContext functionContext, VectorAccessible buildBatch, VectorAccessible probeBatch, VectorAccessible outgoing, HashTable hashTable, JoinRelType joinRelType, List<BuildInfo> buildInfos, List<ArrowBuf> startIndices, List<BitSet> keyMatchBitVectors, int maxHashTableIndex, int targetRecordsPerBatch) { links = new ArrowBuf[buildInfos.size()]; for (int i =0; i < links.length; i++) { links[i] = buildInfos.get(i).getLinks(); } starts = new ArrowBuf[startIndices.size()]; this.keyMatches = new BitSet[keyMatchBitVectors.size()]; if (startIndices.size() > 0) { this.maxOffsetForLastBatch = maxHashTableIndex - (startIndices.size() - 1) * HashTable.BATCH_SIZE; } else { this.maxOffsetForLastBatch = -1; } for (int i = 0; i < starts.length; i++) { starts[i] = startIndices.get(i); keyMatches[i] = keyMatchBitVectors.get(i); } this.probeBatch = probeBatch; this.projectUnmatchedProbe = joinRelType == JoinRelType.LEFT || joinRelType == JoinRelType.FULL; this.projectUnmatchedBuild = joinRelType == JoinRelType.RIGHT || joinRelType == JoinRelType.FULL; this.hashTable = hashTable; this.targetRecordsPerBatch = targetRecordsPerBatch; doSetup(functionContext, buildBatch, probeBatch, outgoing); }
Example 17
Source File: VectorizedProbe.java From dremio-oss with Apache License 2.0 | 4 votes |
public void setup( BufferAllocator allocator, final ExpandableHyperContainer buildBatch, final VectorAccessible probeBatch, // Contains all vectors in probe side output final List<FieldVector> probeOutputs, /* Contains only carry over vectors in build side output for VECTORIZED_GENERIC * Contains all field vectors in build side output for VECTORIZED_BIGINT */ final List<FieldVector> buildOutputs, /* Contains the key field vectors in incoming probe side batch for VECTORIZED_GENERIC * Only for VECTORIZED_GENERIC */ final List<FieldVector> probeIncomingKeys, /* Contains the key field vectors in build side output for VECTORIZED_GENERIC * Only for VECTORIZED_GENERIC */ final List<FieldVector> buildOutputKeys, VectorizedHashJoinOperator.Mode mode, JoinRelType joinRelType, List<BuildInfo> buildInfos, List<ArrowBuf> startIndices, List<MatchBitSet> keyMatchBitVectors, int maxHashTableIndex, JoinTable table, // Used to pivot the keys in incoming build batch into hash table PivotDef pivot, // Used to unpivot the keys in hash table to build side output PivotDef buildUnpivot, int targetRecordsPerBatch, final NullComparator nullMask){ this.nullMask = nullMask; this.pivot = pivot; this.buildUnpivot = buildUnpivot; this.allocator = allocator; this.table = table; this.links = new ArrowBuf[buildInfos.size()]; for (int i =0; i < links.length; i++) { links[i] = buildInfos.get(i).getLinks(); } this.starts = new ArrowBuf[startIndices.size()]; this.keyMatches = new MatchBitSet[keyMatchBitVectors.size()]; if (startIndices.size() > 0) { this.maxOffsetForLastBatch = maxHashTableIndex - (startIndices.size() - 1) * HashTable.BATCH_SIZE; } else { this.maxOffsetForLastBatch = -1; } this.maxHashTableIndex = maxHashTableIndex; for (int i = 0; i < starts.length; i++) { starts[i] = startIndices.get(i); keyMatches[i] = keyMatchBitVectors.get(i); } this.projectUnmatchedBuild = joinRelType == JoinRelType.RIGHT || joinRelType == JoinRelType.FULL; this.projectUnmatchedProbe = joinRelType == JoinRelType.LEFT || joinRelType == JoinRelType.FULL; this.targetRecordsPerBatch = targetRecordsPerBatch; this.projectProbeSv2 = allocator.buffer(targetRecordsPerBatch * BATCH_OFFSET_SIZE); this.probeSv2Addr = projectProbeSv2.memoryAddress(); // first 4 bytes (int) are for batch index and rest 2 bytes are offset within the batch this.projectBuildOffsetBuf = allocator.buffer(targetRecordsPerBatch * BUILD_RECORD_LINK_SIZE); this.projectBuildOffsetAddr = projectBuildOffsetBuf.memoryAddress(); this.projectBuildKeyOffsetBuf = allocator.buffer(targetRecordsPerBatch * ORDINAL_SIZE); this.projectBuildKeyOffsetAddr = projectBuildKeyOffsetBuf.memoryAddress(); this.mode = mode; this.buildOutputs = buildOutputs; if (table.size() > 0) { this.buildCopiers = projectUnmatchedProbe ? ConditionalFieldBufferCopier6.getFourByteCopiers(VectorContainer.getHyperFieldVectors(buildBatch), buildOutputs) : FieldBufferCopier6.getFourByteCopiers(VectorContainer.getHyperFieldVectors(buildBatch), buildOutputs); } else { this.buildCopiers = Collections.emptyList(); } /* For VECTORIZED_GENERIC, we don't keep the key vectors in hyper container, * and then we need to copy keys from probe batch to build side in output for matched and non matched records, * otherwise eight byte hash table is used, we keep the key vector in hyper container, * and then we don't need to copy keys from probe batch to build side in output for matched and non matched records. */ if (this.mode == VectorizedHashJoinOperator.Mode.VECTORIZED_GENERIC) { // create copier for copying keys from probe batch to build side output if (probeIncomingKeys.size() > 0) { this.keysCopiers = FieldBufferCopier.getCopiers(probeIncomingKeys, buildOutputKeys); } else { this.keysCopiers = Collections.emptyList(); } this.projectNullKeyOffset = allocator.buffer(targetRecordsPerBatch * BATCH_OFFSET_SIZE); this.projectNullKeyOffsetAddr = projectNullKeyOffset.memoryAddress(); } else { this.projectNullKeyOffsetAddr = 0; this.keysCopiers = null; } this.probeCopiers = FieldBufferCopier.getCopiers(VectorContainer.getFieldVectors(probeBatch), probeOutputs); }
Example 18
Source File: FlinkJoinToMultiJoinRule.java From flink with Apache License 2.0 | 4 votes |
public void onMatch(RelOptRuleCall call) { final Join origJoin = call.rel(0); final RelNode left = call.rel(1); final RelNode right = call.rel(2); // combine the children MultiJoin inputs into an array of inputs // for the new MultiJoin final List<ImmutableBitSet> projFieldsList = new ArrayList<>(); final List<int[]> joinFieldRefCountsList = new ArrayList<>(); final List<RelNode> newInputs = combineInputs( origJoin, left, right, projFieldsList, joinFieldRefCountsList); // combine the outer join information from the left and right // inputs, and include the outer join information from the current // join, if it's a left/right outer join final List<Pair<JoinRelType, RexNode>> joinSpecs = new ArrayList<>(); combineOuterJoins( origJoin, newInputs, left, right, joinSpecs); // pull up the join filters from the children MultiJoinRels and // combine them with the join filter associated with this LogicalJoin to // form the join filter for the new MultiJoin List<RexNode> newJoinFilters = combineJoinFilters(origJoin, left, right); // add on the join field reference counts for the join condition // associated with this LogicalJoin final com.google.common.collect.ImmutableMap<Integer, ImmutableIntList> newJoinFieldRefCountsMap = addOnJoinFieldRefCounts(newInputs, origJoin.getRowType().getFieldCount(), origJoin.getCondition(), joinFieldRefCountsList); List<RexNode> newPostJoinFilters = combinePostJoinFilters(origJoin, left, right); final RexBuilder rexBuilder = origJoin.getCluster().getRexBuilder(); RelNode multiJoin = new MultiJoin( origJoin.getCluster(), newInputs, RexUtil.composeConjunction(rexBuilder, newJoinFilters), origJoin.getRowType(), origJoin.getJoinType() == JoinRelType.FULL, Pair.right(joinSpecs), Pair.left(joinSpecs), projFieldsList, newJoinFieldRefCountsMap, RexUtil.composeConjunction(rexBuilder, newPostJoinFilters, true)); call.transformTo(multiJoin); }
Example 19
Source File: JoinToMultiJoinRule.java From calcite with Apache License 2.0 | 4 votes |
public void onMatch(RelOptRuleCall call) { final Join origJoin = call.rel(0); final RelNode left = call.rel(1); final RelNode right = call.rel(2); // combine the children MultiJoin inputs into an array of inputs // for the new MultiJoin final List<ImmutableBitSet> projFieldsList = new ArrayList<>(); final List<int[]> joinFieldRefCountsList = new ArrayList<>(); final List<RelNode> newInputs = combineInputs( origJoin, left, right, projFieldsList, joinFieldRefCountsList); // combine the outer join information from the left and right // inputs, and include the outer join information from the current // join, if it's a left/right outer join final List<Pair<JoinRelType, RexNode>> joinSpecs = new ArrayList<>(); combineOuterJoins( origJoin, newInputs, left, right, joinSpecs); // pull up the join filters from the children MultiJoinRels and // combine them with the join filter associated with this LogicalJoin to // form the join filter for the new MultiJoin List<RexNode> newJoinFilters = combineJoinFilters(origJoin, left, right); // add on the join field reference counts for the join condition // associated with this LogicalJoin final ImmutableMap<Integer, ImmutableIntList> newJoinFieldRefCountsMap = addOnJoinFieldRefCounts(newInputs, origJoin.getRowType().getFieldCount(), origJoin.getCondition(), joinFieldRefCountsList); List<RexNode> newPostJoinFilters = combinePostJoinFilters(origJoin, left, right); final RexBuilder rexBuilder = origJoin.getCluster().getRexBuilder(); RelNode multiJoin = new MultiJoin( origJoin.getCluster(), newInputs, RexUtil.composeConjunction(rexBuilder, newJoinFilters), origJoin.getRowType(), origJoin.getJoinType() == JoinRelType.FULL, Pair.right(joinSpecs), Pair.left(joinSpecs), projFieldsList, newJoinFieldRefCountsMap, RexUtil.composeConjunction(rexBuilder, newPostJoinFilters, true)); call.transformTo(multiJoin); }
Example 20
Source File: JoinNode.java From calcite with Apache License 2.0 | 4 votes |
public void run() throws InterruptedException { final int fieldCount = rel.getLeft().getRowType().getFieldCount() + rel.getRight().getRowType().getFieldCount(); context.values = new Object[fieldCount]; // source for the outer relation of nested loop Source outerSource = leftSource; // source for the inner relation of nested loop Source innerSource = rightSource; if (rel.getJoinType() == JoinRelType.RIGHT) { outerSource = rightSource; innerSource = leftSource; } // row from outer source Row outerRow = null; // rows from inner source List<Row> innerRows = null; Set<Row> matchRowSet = new HashSet<>(); while ((outerRow = outerSource.receive()) != null) { if (innerRows == null) { innerRows = new ArrayList<Row>(); Row innerRow = null; while ((innerRow = innerSource.receive()) != null) { innerRows.add(innerRow); } } matchRowSet.addAll(doJoin(outerRow, innerRows, rel.getJoinType())); } if (rel.getJoinType() == JoinRelType.FULL) { // send un-match rows for full join on right source List<Row> empty = new ArrayList<>(); for (Row row: innerRows) { if (matchRowSet.contains(row)) { continue; } doSend(row, empty, JoinRelType.RIGHT); } } }