use of org.apache.flink.table.api.TableException in project flink by apache.
the class StreamExecMatch method translateToPlanInternal.
@SuppressWarnings("unchecked")
@Override
protected Transformation<RowData> translateToPlanInternal(PlannerBase planner, ExecNodeConfig config) {
final ExecEdge inputEdge = getInputEdges().get(0);
final Transformation<RowData> inputTransform = (Transformation<RowData>) inputEdge.translateToPlan(planner);
final RowType inputRowType = (RowType) inputEdge.getOutputType();
checkOrderKeys(inputRowType);
final EventComparator<RowData> eventComparator = createEventComparator(config, inputRowType);
final Transformation<RowData> timestampedInputTransform = translateOrder(inputTransform, inputRowType);
final Tuple2<Pattern<RowData, RowData>, List<String>> cepPatternAndNames = translatePattern(matchSpec, config.getTableConfig(), planner.getRelBuilder(), inputRowType);
final Pattern<RowData, RowData> cepPattern = cepPatternAndNames.f0;
// TODO remove this once it is supported in CEP library
if (NFACompiler.canProduceEmptyMatches(cepPattern)) {
throw new TableException("Patterns that can produce empty matches are not supported. There must be at least one non-optional state.");
}
// TODO remove this once it is supported in CEP library
if (cepPattern.getQuantifier().hasProperty(Quantifier.QuantifierProperty.GREEDY)) {
throw new TableException("Greedy quantifiers are not allowed as the last element of a Pattern yet. " + "Finish your pattern with either a simple variable or reluctant quantifier.");
}
if (matchSpec.isAllRows()) {
throw new TableException("All rows per match mode is not supported yet.");
}
final int[] partitionKeys = matchSpec.getPartition().getFieldIndices();
final SortSpec.SortFieldSpec timeOrderField = matchSpec.getOrderKeys().getFieldSpec(0);
final LogicalType timeOrderFieldType = inputRowType.getTypeAt(timeOrderField.getFieldIndex());
final boolean isProctime = TypeCheckUtils.isProcTime(timeOrderFieldType);
final InternalTypeInfo<RowData> inputTypeInfo = (InternalTypeInfo<RowData>) inputTransform.getOutputType();
final TypeSerializer<RowData> inputSerializer = inputTypeInfo.createSerializer(planner.getExecEnv().getConfig());
final NFACompiler.NFAFactory<RowData> nfaFactory = NFACompiler.compileFactory(cepPattern, false);
final MatchCodeGenerator generator = new MatchCodeGenerator(new CodeGeneratorContext(config.getTableConfig()), planner.getRelBuilder(), // nullableInput
false, JavaScalaConversionUtil.toScala(cepPatternAndNames.f1), JavaScalaConversionUtil.toScala(Optional.empty()), CodeGenUtils.DEFAULT_COLLECTOR_TERM());
generator.bindInput(inputRowType, CodeGenUtils.DEFAULT_INPUT1_TERM(), JavaScalaConversionUtil.toScala(Optional.empty()));
final PatternProcessFunctionRunner patternProcessFunction = generator.generateOneRowPerMatchExpression((RowType) getOutputType(), partitionKeys, matchSpec.getMeasures());
final CepOperator<RowData, RowData, RowData> operator = new CepOperator<>(inputSerializer, isProctime, nfaFactory, eventComparator, cepPattern.getAfterMatchSkipStrategy(), patternProcessFunction, null);
final OneInputTransformation<RowData, RowData> transform = ExecNodeUtil.createOneInputTransformation(timestampedInputTransform, createTransformationMeta(MATCH_TRANSFORMATION, config), operator, InternalTypeInfo.of(getOutputType()), timestampedInputTransform.getParallelism());
final RowDataKeySelector selector = KeySelectorUtil.getRowDataSelector(partitionKeys, inputTypeInfo);
transform.setStateKeySelector(selector);
transform.setStateKeyType(selector.getProducedType());
if (inputsContainSingleton()) {
transform.setParallelism(1);
transform.setMaxParallelism(1);
}
return transform;
}
use of org.apache.flink.table.api.TableException in project flink by apache.
the class StreamExecMatch method checkOrderKeys.
private void checkOrderKeys(RowType inputRowType) {
SortSpec orderKeys = matchSpec.getOrderKeys();
if (orderKeys.getFieldSize() == 0) {
throw new TableException("You must specify either rowtime or proctime for order by.");
}
SortSpec.SortFieldSpec timeOrderField = orderKeys.getFieldSpec(0);
int timeOrderFieldIdx = timeOrderField.getFieldIndex();
LogicalType timeOrderFieldType = inputRowType.getTypeAt(timeOrderFieldIdx);
// need to identify time between others order fields. Time needs to be first sort element
if (!TypeCheckUtils.isRowTime(timeOrderFieldType) && !TypeCheckUtils.isProcTime(timeOrderFieldType)) {
throw new TableException("You must specify either rowtime or proctime for order by as the first one.");
}
// time ordering needs to be ascending
if (!orderKeys.getAscendingOrders()[0]) {
throw new TableException("Primary sort order of a streaming table must be ascending on time.");
}
}
use of org.apache.flink.table.api.TableException in project flink by apache.
the class StreamExecOverAggregate method translateToPlanInternal.
@SuppressWarnings("unchecked")
@Override
protected Transformation<RowData> translateToPlanInternal(PlannerBase planner, ExecNodeConfig config) {
if (overSpec.getGroups().size() > 1) {
throw new TableException("All aggregates must be computed on the same window.");
}
final OverSpec.GroupSpec group = overSpec.getGroups().get(0);
final int[] orderKeys = group.getSort().getFieldIndices();
final boolean[] isAscendingOrders = group.getSort().getAscendingOrders();
if (orderKeys.length != 1 || isAscendingOrders.length != 1) {
throw new TableException("The window can only be ordered by a single time column.");
}
if (!isAscendingOrders[0]) {
throw new TableException("The window can only be ordered in ASCENDING mode.");
}
final int[] partitionKeys = overSpec.getPartition().getFieldIndices();
if (partitionKeys.length > 0 && config.getStateRetentionTime() < 0) {
LOG.warn("No state retention interval configured for a query which accumulates state. " + "Please provide a query configuration with valid retention interval to prevent " + "excessive state size. You may specify a retention time of 0 to not clean up the state.");
}
final ExecEdge inputEdge = getInputEdges().get(0);
final Transformation<RowData> inputTransform = (Transformation<RowData>) inputEdge.translateToPlan(planner);
final RowType inputRowType = (RowType) inputEdge.getOutputType();
final int orderKey = orderKeys[0];
final LogicalType orderKeyType = inputRowType.getFields().get(orderKey).getType();
// check time field && identify window rowtime attribute
final int rowTimeIdx;
if (isRowtimeAttribute(orderKeyType)) {
rowTimeIdx = orderKey;
} else if (isProctimeAttribute(orderKeyType)) {
rowTimeIdx = -1;
} else {
throw new TableException("OVER windows' ordering in stream mode must be defined on a time attribute.");
}
final List<RexLiteral> constants = overSpec.getConstants();
final List<String> fieldNames = new ArrayList<>(inputRowType.getFieldNames());
final List<LogicalType> fieldTypes = new ArrayList<>(inputRowType.getChildren());
IntStream.range(0, constants.size()).forEach(i -> fieldNames.add("TMP" + i));
for (int i = 0; i < constants.size(); ++i) {
fieldNames.add("TMP" + i);
fieldTypes.add(FlinkTypeFactory.toLogicalType(constants.get(i).getType()));
}
final RowType aggInputRowType = RowType.of(fieldTypes.toArray(new LogicalType[0]), fieldNames.toArray(new String[0]));
final CodeGeneratorContext ctx = new CodeGeneratorContext(config.getTableConfig());
final KeyedProcessFunction<RowData, RowData, RowData> overProcessFunction;
if (group.getLowerBound().isPreceding() && group.getLowerBound().isUnbounded() && group.getUpperBound().isCurrentRow()) {
// unbounded OVER window
overProcessFunction = createUnboundedOverProcessFunction(ctx, group.getAggCalls(), constants, aggInputRowType, inputRowType, rowTimeIdx, group.isRows(), config, planner.getRelBuilder());
} else if (group.getLowerBound().isPreceding() && !group.getLowerBound().isUnbounded() && group.getUpperBound().isCurrentRow()) {
final Object boundValue = OverAggregateUtil.getBoundary(overSpec, group.getLowerBound());
if (boundValue instanceof BigDecimal) {
throw new TableException("the specific value is decimal which haven not supported yet.");
}
// bounded OVER window
final long precedingOffset = -1 * (long) boundValue + (group.isRows() ? 1 : 0);
overProcessFunction = createBoundedOverProcessFunction(ctx, group.getAggCalls(), constants, aggInputRowType, inputRowType, rowTimeIdx, group.isRows(), precedingOffset, config, planner.getRelBuilder());
} else {
throw new TableException("OVER RANGE FOLLOWING windows are not supported yet.");
}
final KeyedProcessOperator<RowData, RowData, RowData> operator = new KeyedProcessOperator<>(overProcessFunction);
OneInputTransformation<RowData, RowData> transform = ExecNodeUtil.createOneInputTransformation(inputTransform, createTransformationMeta(OVER_AGGREGATE_TRANSFORMATION, config), operator, InternalTypeInfo.of(getOutputType()), inputTransform.getParallelism());
// set KeyType and Selector for state
final RowDataKeySelector selector = KeySelectorUtil.getRowDataSelector(partitionKeys, InternalTypeInfo.of(inputRowType));
transform.setStateKeySelector(selector);
transform.setStateKeyType(selector.getProducedType());
return transform;
}
use of org.apache.flink.table.api.TableException in project flink by apache.
the class StreamExecPythonOverAggregate method getPythonOverWindowAggregateFunctionOperator.
@SuppressWarnings("unchecked")
private OneInputStreamOperator<RowData, RowData> getPythonOverWindowAggregateFunctionOperator(ExecNodeConfig config, Configuration pythonConfig, RowType inputRowType, RowType outputRowType, int rowTiemIdx, long lowerBoundary, boolean isRowsClause, int[] udafInputOffsets, PythonFunctionInfo[] pythonFunctionInfos, long minIdleStateRetentionTime, long maxIdleStateRetentionTime) {
RowType userDefinedFunctionInputType = (RowType) Projection.of(udafInputOffsets).project(inputRowType);
RowType userDefinedFunctionOutputType = (RowType) Projection.range(inputRowType.getFieldCount(), outputRowType.getFieldCount()).project(outputRowType);
GeneratedProjection generatedProjection = ProjectionCodeGenerator.generateProjection(CodeGeneratorContext.apply(config.getTableConfig()), "UdafInputProjection", inputRowType, userDefinedFunctionInputType, udafInputOffsets);
if (isRowsClause) {
String className;
if (rowTiemIdx != -1) {
className = ARROW_PYTHON_OVER_WINDOW_ROWS_ROW_TIME_AGGREGATE_FUNCTION_OPERATOR_NAME;
} else {
className = ARROW_PYTHON_OVER_WINDOW_ROWS_PROC_TIME_AGGREGATE_FUNCTION_OPERATOR_NAME;
}
Class<?> clazz = CommonPythonUtil.loadClass(className);
try {
Constructor<?> ctor = clazz.getConstructor(Configuration.class, long.class, long.class, PythonFunctionInfo[].class, RowType.class, RowType.class, RowType.class, int.class, long.class, GeneratedProjection.class);
return (OneInputStreamOperator<RowData, RowData>) ctor.newInstance(pythonConfig, minIdleStateRetentionTime, maxIdleStateRetentionTime, pythonFunctionInfos, inputRowType, userDefinedFunctionInputType, userDefinedFunctionOutputType, rowTiemIdx, lowerBoundary, generatedProjection);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new TableException("Python Arrow Over Rows Window Function Operator constructed failed.", e);
}
} else {
String className;
if (rowTiemIdx != -1) {
className = ARROW_PYTHON_OVER_WINDOW_RANGE_ROW_TIME_AGGREGATE_FUNCTION_OPERATOR_NAME;
} else {
className = ARROW_PYTHON_OVER_WINDOW_RANGE_PROC_TIME_AGGREGATE_FUNCTION_OPERATOR_NAME;
}
Class<?> clazz = CommonPythonUtil.loadClass(className);
try {
Constructor<?> ctor = clazz.getConstructor(Configuration.class, PythonFunctionInfo[].class, RowType.class, RowType.class, RowType.class, int.class, long.class, GeneratedProjection.class);
return (OneInputStreamOperator<RowData, RowData>) ctor.newInstance(pythonConfig, pythonFunctionInfos, inputRowType, userDefinedFunctionInputType, userDefinedFunctionOutputType, rowTiemIdx, lowerBoundary, generatedProjection);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new TableException("Python Arrow Over Range Window Function Operator constructed failed.", e);
}
}
}
use of org.apache.flink.table.api.TableException in project flink by apache.
the class StreamExecPythonOverAggregate method translateToPlanInternal.
@SuppressWarnings("unchecked")
@Override
protected Transformation<RowData> translateToPlanInternal(PlannerBase planner, ExecNodeConfig config) {
if (overSpec.getGroups().size() > 1) {
throw new TableException("All aggregates must be computed on the same window.");
}
final OverSpec.GroupSpec group = overSpec.getGroups().get(0);
final int[] orderKeys = group.getSort().getFieldIndices();
final boolean[] isAscendingOrders = group.getSort().getAscendingOrders();
if (orderKeys.length != 1 || isAscendingOrders.length != 1) {
throw new TableException("The window can only be ordered by a single time column.");
}
if (!isAscendingOrders[0]) {
throw new TableException("The window can only be ordered in ASCENDING mode.");
}
final int[] partitionKeys = overSpec.getPartition().getFieldIndices();
if (partitionKeys.length > 0 && config.getStateRetentionTime() < 0) {
LOG.warn("No state retention interval configured for a query which accumulates state. " + "Please provide a query configuration with valid retention interval to prevent " + "excessive state size. You may specify a retention time of 0 to not clean up the state.");
}
final ExecEdge inputEdge = getInputEdges().get(0);
final Transformation<RowData> inputTransform = (Transformation<RowData>) inputEdge.translateToPlan(planner);
final RowType inputRowType = (RowType) inputEdge.getOutputType();
final int orderKey = orderKeys[0];
final LogicalType orderKeyType = inputRowType.getFields().get(orderKey).getType();
// check time field && identify window rowtime attribute
final int rowTimeIdx;
if (isRowtimeAttribute(orderKeyType)) {
rowTimeIdx = orderKey;
} else if (isProctimeAttribute(orderKeyType)) {
rowTimeIdx = -1;
} else {
throw new TableException("OVER windows' ordering in stream mode must be defined on a time attribute.");
}
if (group.getLowerBound().isPreceding() && group.getLowerBound().isUnbounded()) {
throw new TableException("Python UDAF is not supported to be used in UNBOUNDED PRECEDING OVER windows.");
} else if (!group.getUpperBound().isCurrentRow()) {
throw new TableException("Python UDAF is not supported to be used in UNBOUNDED FOLLOWING OVER windows.");
}
Object boundValue = OverAggregateUtil.getBoundary(overSpec, group.getLowerBound());
if (boundValue instanceof BigDecimal) {
throw new TableException("the specific value is decimal which haven not supported yet.");
}
long precedingOffset = -1 * (long) boundValue;
Configuration pythonConfig = CommonPythonUtil.getMergedConfig(planner.getExecEnv(), config.getTableConfig());
OneInputTransformation<RowData, RowData> transform = createPythonOneInputTransformation(inputTransform, inputRowType, InternalTypeInfo.of(getOutputType()).toRowType(), rowTimeIdx, group.getAggCalls().toArray(new AggregateCall[0]), precedingOffset, group.isRows(), config.getStateRetentionTime(), config.getMaxIdleStateRetentionTime(), pythonConfig, config);
if (CommonPythonUtil.isPythonWorkerUsingManagedMemory(pythonConfig)) {
transform.declareManagedMemoryUseCaseAtSlotScope(ManagedMemoryUseCase.PYTHON);
}
// set KeyType and Selector for state
final RowDataKeySelector selector = KeySelectorUtil.getRowDataSelector(partitionKeys, InternalTypeInfo.of(inputRowType));
transform.setStateKeySelector(selector);
transform.setStateKeyType(selector.getProducedType());
return transform;
}
Aggregations