SamzaSqlRelMessageJoinFunction(JoinRelType joinRelType, boolean isTablePosOnRight, List<Integer> streamFieldIds, List<String> streamFieldNames, List<String> tableFieldNames) { this.joinRelType = joinRelType; this.isTablePosOnRight = isTablePosOnRight; Validate.isTrue((joinRelType.compareTo(JoinRelType.LEFT) == 0 && isTablePosOnRight) || (joinRelType.compareTo(JoinRelType.RIGHT) == 0 && !isTablePosOnRight) || joinRelType.compareTo(JoinRelType.INNER) == 0); this.streamFieldIds = new ArrayList<>(streamFieldIds); this.tableFieldNames = new ArrayList<>(tableFieldNames); this.outFieldNames = new ArrayList<>(); if (isTablePosOnRight) { outFieldNames.addAll(streamFieldNames); } outFieldNames.addAll(tableFieldNames); if (!isTablePosOnRight) { outFieldNames.addAll(streamFieldNames); } }
SamzaSqlTableJoinFunction(JoinInputNode streamNode, JoinInputNode tableNode, JoinRelType joinRelType) { this.joinRelType = joinRelType; this.isTablePosOnRight = tableNode.isPosOnRight(); Validate.isTrue((joinRelType.compareTo(JoinRelType.LEFT) == 0 && isTablePosOnRight) || (joinRelType.compareTo(JoinRelType.RIGHT) == 0 && !isTablePosOnRight) || joinRelType.compareTo(JoinRelType.INNER) == 0); this.streamFieldIds = new ArrayList<>(streamNode.getKeyIds()); this.tableKeyIds = new ArrayList<>(tableNode.getKeyIds()); this.tableFieldNames = new ArrayList<>(tableNode.getFieldNames()); this.outFieldNames = new ArrayList<>(); if (isTablePosOnRight) { outFieldNames.addAll(streamNode.getFieldNames()); outFieldNames.addAll(tableFieldNames); } else { outFieldNames.addAll(tableFieldNames); outFieldNames.addAll(streamNode.getFieldNames()); } }
private void validateJoinQuery(LogicalJoin join, JoinInputNode.InputType inputTypeOnLeft, JoinInputNode.InputType inputTypeOnRight) { JoinRelType joinRelType = join.getJoinType(); if (joinRelType.compareTo(JoinRelType.INNER) != 0 && joinRelType.compareTo(JoinRelType.LEFT) != 0 && joinRelType.compareTo(JoinRelType.RIGHT) != 0) { throw new SamzaException("Query with only INNER and LEFT/RIGHT OUTER join are supported."); } boolean isTablePosOnLeft = (inputTypeOnLeft != JoinInputNode.InputType.STREAM); boolean isTablePosOnRight = (inputTypeOnRight != JoinInputNode.InputType.STREAM); if (!isTablePosOnLeft && !isTablePosOnRight) { throw new SamzaException("Invalid query with both sides of join being denoted as 'stream'. " + "Stream-stream join is not yet supported. " + dumpRelPlanForNode(join)); } if (isTablePosOnLeft && isTablePosOnRight) { throw new SamzaException("Invalid query with both sides of join being denoted as 'table'. " + dumpRelPlanForNode(join)); } if (joinRelType.compareTo(JoinRelType.LEFT) == 0 && isTablePosOnLeft && !isTablePosOnRight) { throw new SamzaException("Invalid query for outer left join. Left side of the join should be a 'stream' and " + "right side of join should be a 'table'. " + dumpRelPlanForNode(join)); } if (joinRelType.compareTo(JoinRelType.RIGHT) == 0 && isTablePosOnRight && !isTablePosOnLeft) { throw new SamzaException("Invalid query for outer right join. Left side of the join should be a 'table' and " + "right side of join should be a 'stream'. " + dumpRelPlanForNode(join)); } validateJoinCondition(join.getCondition()); }
@Override public SamzaSqlRelMessage apply(SamzaSqlRelMessage message, R record) { if (joinRelType.compareTo(JoinRelType.INNER) == 0 && record == null) { log.debug("Inner Join: Record not found for the message with key: " + getMessageKey(message)); // Returning null would result in Join operator implementation to filter out the message. return null; } // The resulting join output should be a SamzaSqlRelMessage containing the fields from both the stream message and // table record. The order of stream message fields and table record fields are dictated by the position of stream // and table in the 'from' clause of sql query. The output should also include the keys from both the stream message // and the table record. List<Object> outFieldValues = new ArrayList<>(); // If table position is on the right, add the stream message fields first if (isTablePosOnRight) { outFieldValues.addAll(message.getSamzaSqlRelRecord().getFieldValues()); } // Add the table record fields. if (record != null) { outFieldValues.addAll(getTableRelRecordFieldValues(record)); } else { // Table record could be null as the record could not be found in the store. This can // happen for outer joins. Add nulls to all the field values in the output message. tableFieldNames.forEach(s -> outFieldValues.add(null)); } // If table position is on the left, add the stream message fields last if (!isTablePosOnRight) { outFieldValues.addAll(message.getSamzaSqlRelRecord().getFieldValues()); } return new SamzaSqlRelMessage(outFieldNames, outFieldValues, message.getSamzaSqlRelMsgMetadata()); }
@Override public SamzaSqlRelMessage apply(SamzaSqlRelMessage message, KV<SamzaSqlCompositeKey, SamzaSqlRelMessage> record) { if (joinRelType.compareTo(JoinRelType.INNER) == 0 && record == null) { log.debug("Inner Join: Record not found for the message with key: " + getMessageKey(message)); // Returning null would result in Join operator implementation to filter out the message. return null; } // The resulting join output should be a SamzaSqlRelMessage containing the fields from both the stream message and // table record. The order of stream message fields and table record fields are dictated by the position of stream // and table in the 'from' clause of sql query. The output should also include the keys from both the stream message // and the table record. List<Object> outFieldValues = new ArrayList<>(); // If table position is on the right, add the stream message fields first if (isTablePosOnRight) { outFieldValues.addAll(message.getSamzaSqlRelRecord().getFieldValues()); } // Add the table record fields. if (record != null) { outFieldValues.addAll(record.getValue().getSamzaSqlRelRecord().getFieldValues()); } else { // Table record could be null as the record could not be found in the store. This can // happen for outer joins. Add nulls to all the field values in the output message. tableFieldNames.forEach(s -> outFieldValues.add(null)); } // If table position is on the left, add the stream message fields last if (!isTablePosOnRight) { outFieldValues.addAll(message.getSamzaSqlRelRecord().getFieldValues()); } return new SamzaSqlRelMessage(outFieldNames, outFieldValues); }
private void validateJoinQuery(LogicalJoin join) { JoinRelType joinRelType = join.getJoinType(); if (joinRelType.compareTo(JoinRelType.INNER) != 0 && joinRelType.compareTo(JoinRelType.LEFT) != 0 && joinRelType.compareTo(JoinRelType.RIGHT) != 0) { throw new SamzaException("Query with only INNER and LEFT/RIGHT OUTER join are supported."); } boolean isTablePosOnLeft = isTable(join.getLeft()); boolean isTablePosOnRight = isTable(join.getRight()); if (!isTablePosOnLeft && !isTablePosOnRight) { throw new SamzaException("Invalid query with both sides of join being denoted as 'stream'. " + "Stream-stream join is not yet supported. " + dumpRelPlanForNode(join)); } if (isTablePosOnLeft && isTablePosOnRight) { throw new SamzaException("Invalid query with both sides of join being denoted as 'table'. " + dumpRelPlanForNode(join)); } if (joinRelType.compareTo(JoinRelType.LEFT) == 0 && isTablePosOnLeft && !isTablePosOnRight) { throw new SamzaException("Invalid query for outer left join. Left side of the join should be a 'stream' and " + "right side of join should be a 'table'. " + dumpRelPlanForNode(join)); } if (joinRelType.compareTo(JoinRelType.RIGHT) == 0 && isTablePosOnRight && !isTablePosOnLeft) { throw new SamzaException("Invalid query for outer right join. Left side of the join should be a 'table' and " + "right side of join should be a 'stream'. " + dumpRelPlanForNode(join)); } validateJoinCondition(join.getCondition()); }