Apache flink 使用表AggregateFunction和ResultTypeQueryable时的ValidationException

Apache flink 使用表AggregateFunction和ResultTypeQueryable时的ValidationException,apache-flink,Apache Flink,我正在使用配置为使用Flink表的本地flink1.6集群jar (这意味着我的程序的jar不包括flink表)。 使用以下代码 import org.apache.flink.api.common.typeinfo.TypeHint; import org.apache.flink.api.common.typeinfo.TypeInformation; import org.apache.flink.api.java.ExecutionEnvironment; import org.apac

我正在使用配置为使用
Flink表的本地flink1.6集群
jar (这意味着我的程序的jar不包括
flink表
)。 使用以下代码

import org.apache.flink.api.common.typeinfo.TypeHint;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.typeutils.ResultTypeQueryable;
import org.apache.flink.table.api.Table;
import org.apache.flink.table.api.TableEnvironment;
import org.apache.flink.table.api.java.BatchTableEnvironment;
import org.apache.flink.table.functions.AggregateFunction;
import org.apache.flink.types.Row;

import java.util.ArrayList;
import java.util.List;

public class JMain {
    public static void main(String[] args) throws Exception {
        ExecutionEnvironment execEnv = ExecutionEnvironment.getExecutionEnvironment();
        BatchTableEnvironment tableEnv = TableEnvironment.getTableEnvironment(execEnv);

        tableEnv.registerFunction("enlist", new Enlister());

        DataSource<Tuple2<String, String>> source = execEnv.fromElements(
                new Tuple2<>("a", "1"),
                new Tuple2<>("a", "2"),
                new Tuple2<>("b", "3")
        );

        Table table = tableEnv.fromDataSet(source, "a, b")
                .groupBy("a")
                .select("enlist(a, b)");

        tableEnv.toDataSet(table, Row.class)
                .print();
    }

    public static class Enlister
            extends AggregateFunction<List<String>, ArrayList<String>>
            implements ResultTypeQueryable<List<String>>
    {
        @Override
        public ArrayList<String> createAccumulator() {
            return new ArrayList<>();
        }

        @Override
        public List<String> getValue(ArrayList<String> acc) {
            return acc;
        }

        @SuppressWarnings("unused")
        public void accumulate(ArrayList<String> acc, String a, String b) {
            acc.add(a + ":" + b);
        }

        @SuppressWarnings("unused")
        public void merge(ArrayList<String> acc, Iterable<ArrayList<String>> it) {
            for (ArrayList<String> otherAcc : it) {
                acc.addAll(otherAcc);
            }
        }

        @SuppressWarnings("unused")
        public void resetAccumulator(ArrayList<String> acc) {
            acc.clear();
        }

        @Override
        public TypeInformation<List<String>> getProducedType() {
            return TypeInformation.of(new TypeHint<List<String>>(){});
        }
    }
}
但是,如果我没有实现
ResultTypeQueryable
, 我得到了预期的输出:

Starting execution of program
[b:3]
[a:1, a:2]
Program execution finished
Job with JobID 20497bd3efe44fab0092a05a8eb7d9de has finished.
Job Runtime: 270 ms
Accumulator Results: 
- 56e0e5a9466b84ae44431c9c4b7aad71 (java.util.ArrayList) [2 elements]
我的实际用例似乎需要
ResultTypeQueryable
, 因为否则我会得到这个例外:

org.apache.flink.table.api.ValidationException: Expression Enlister(List('a, 'b)) failed on input check: Given parameters do not match any signature. 
Actual: (java.lang.String, java.lang.String) 
Expected: (java.lang.String, java.lang.String)
The return type of function ... could not be determined automatically,
due to type erasure. You can give type information hints by using the
returns(...) method on the result of the transformation call,
or by letting your function implement the 'ResultTypeQueryable' interface

有什么办法可以解决这个问题吗?

在这种情况下,实现
ResultTypeQueryable
是不正确的。这一例外具有误导性。而是重写
getResultType()
getAccumeratorType()
。这背后的原因是泛型在为序列化程序生成类型信息时通常会导致问题(由于Java的类型擦除)。

在这种情况下,实现
ResultTypeQueryable
是不正确的。这一例外具有误导性。而是重写
getResultType()
getAccumeratorType()
。这背后的原因是泛型在为序列化程序生成类型信息时通常会导致问题(由于Java的类型擦除)。

我试图在一个小程序中重现这个问题,但我无法, 这只发生在我的大项目中。 不幸的是,重写
getResultType()
getAccumeratorType()
也没有帮助, 在这种情况下,我得到了一个例外:

java.lang.IndexOutOfBoundsException
    at org.apache.flink.api.java.typeutils.TupleTypeInfoBase.getTypeAt(TupleTypeInfoBase.java:199)
    at org.apache.flink.api.java.typeutils.RowTypeInfo.getTypeAt(RowTypeInfo.java:179)
    at org.apache.flink.api.common.operators.Keys$ExpressionKeys.isSortKey(Keys.java:444)
    at org.apache.flink.api.java.operators.SortPartitionOperator.ensureSortableKey(SortPartitionOperator.java:150)
    at org.apache.flink.api.java.operators.SortPartitionOperator.<init>(SortPartitionOperator.java:75)
    at org.apache.flink.api.java.DataSet.sortPartition(DataSet.java:1414)
java.lang.IndexOutOfBoundsException
位于org.apache.flink.api.java.typeutils.TupleTypeInfoBase.getTypeAt(TupleTypeInfoBase.java:199)
在org.apache.flink.api.java.typeutils.RowTypeInfo.gettypet上(RowTypeInfo.java:179)
位于org.apache.flink.api.common.operators.Keys$ExpressionKeys.isSortKey(Keys.java:444)
位于org.apache.flink.api.java.operators.SortPartitionOperator.EnsureResultableKey(SortPartitionOperator.java:150)
位于org.apache.flink.api.java.operators.SortPartitionOperator。(SortPartitionOperator.java:75)
位于org.apache.flink.api.java.DataSet.sortPartition(DataSet.java:1414)
实际上,即使没有重写,我也得到了那个异常。 唯一对我有效的是:

String[] fieldNames = new String[] {
        "result"
};
TypeInformation<?>[] types = new TypeInformation[] {
        TypeInformation.of(new TypeHint<List<String>>(){})
};

tableEnv.toDataSet(table, Types.ROW(fieldNames, types))...
String[]fieldNames=新字符串[]{
“结果”
};
类型信息[]类型=新类型信息[]{
TypeInformation.of(新的TypeHint(){})
};
tableEnv.toDataSet(表,类型,行(字段名,类型))。。。

我试图在一个小程序中重现这个问题,但我做不到, 这只发生在我的大项目中。 不幸的是,重写
getResultType()
getAccumeratorType()
也没有帮助, 在这种情况下,我得到了一个例外:

java.lang.IndexOutOfBoundsException
    at org.apache.flink.api.java.typeutils.TupleTypeInfoBase.getTypeAt(TupleTypeInfoBase.java:199)
    at org.apache.flink.api.java.typeutils.RowTypeInfo.getTypeAt(RowTypeInfo.java:179)
    at org.apache.flink.api.common.operators.Keys$ExpressionKeys.isSortKey(Keys.java:444)
    at org.apache.flink.api.java.operators.SortPartitionOperator.ensureSortableKey(SortPartitionOperator.java:150)
    at org.apache.flink.api.java.operators.SortPartitionOperator.<init>(SortPartitionOperator.java:75)
    at org.apache.flink.api.java.DataSet.sortPartition(DataSet.java:1414)
java.lang.IndexOutOfBoundsException
位于org.apache.flink.api.java.typeutils.TupleTypeInfoBase.getTypeAt(TupleTypeInfoBase.java:199)
在org.apache.flink.api.java.typeutils.RowTypeInfo.gettypet上(RowTypeInfo.java:179)
位于org.apache.flink.api.common.operators.Keys$ExpressionKeys.isSortKey(Keys.java:444)
位于org.apache.flink.api.java.operators.SortPartitionOperator.EnsureResultableKey(SortPartitionOperator.java:150)
位于org.apache.flink.api.java.operators.SortPartitionOperator。(SortPartitionOperator.java:75)
位于org.apache.flink.api.java.DataSet.sortPartition(DataSet.java:1414)
实际上,即使没有重写,我也得到了那个异常。 唯一对我有效的是:

String[] fieldNames = new String[] {
        "result"
};
TypeInformation<?>[] types = new TypeInformation[] {
        TypeInformation.of(new TypeHint<List<String>>(){})
};

tableEnv.toDataSet(table, Types.ROW(fieldNames, types))...
String[]fieldNames=新字符串[]{
“结果”
};
类型信息[]类型=新类型信息[]{
TypeInformation.of(新的TypeHint(){})
};
tableEnv.toDataSet(表,类型,行(字段名,类型))。。。

您好,我想您可能偶然发现了一个bug。您是否需要扩展
结果类型查询表
?如果是,你能告诉我原因吗?
AggregateFunction
getResultType
对您来说还不够吗?@DawidWysakowicz如果我只覆盖
getResultType
,我会得到:
函数的返回类型。。。由于类型擦除,无法自动确定。您可以通过对转换调用的结果使用returns(…)方法,或者通过让您的函数实现'ResultTypeQueryable'接口来提供类型信息提示。
。您好,我想您可能偶然发现了一个bug。您是否需要扩展
结果类型查询表
?如果是,你能告诉我原因吗?
AggregateFunction
getResultType
对您来说还不够吗?@DawidWysakowicz如果我只覆盖
getResultType
,我会得到:
函数的返回类型。。。由于类型擦除,无法自动确定。您可以通过对转换调用的结果使用returns(…)方法给出类型信息提示,或者在与您相关的情况下让您的函数实现'ResultTypeQueryable'接口
@twalthr。通常,
tableEnv.toDataSet(table,Row.class)
就足够了。如果不是,这是一个错误,应该用一个小的可复制程序来报告。@t如果这与您有关,那么它是一个错误。
tableEnv.toDataSet(table,Row.class)
就足够了。如果不是,这是一个bug,应该用一个可复制的程序来报告。