flink中使用lambda表达式
在
java8
中有一种新的语法糖,即
lambda
表达式,在
flink
中,支持对所有的java api提供了 lambda的支持,但是存在一些限制,此处举一个例子,来说明如何在
flink
中使用
lambda
表达式,以及出错后如何处理。
参考链接:https://ci.apache.org/projects/flink/flink-docs-stable/dev/java_lambdas.html
1、使用lambda的一个示例
/**
* 测试 lambda 表达式在 flink 中的应用
* 不建议使用 lambda 表达式
* <p>
* 参考文章:https://ci.apache.org/projects/flink/flink-docs-stable/dev/java_lambdas.html
*
* @author huan.fu
* @date 2019-11-17 - 13:57
*/
public class FlinkLambdaJob {
public static void main(String[] args) throws Exception {
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
List<String> datas = Arrays.asList("aa,bb,ccc,dd,aa", "cc,dd,ee,ff,gg,aa");
DataSource<String> dataSource = env.fromCollection(datas);
dataSource.flatMap((String input, Collector<String[]> collector) -> {
collector.collect(input.split(","));
})
.flatMap((String[] words, Collector<Tuple2<String, Integer>> collector) -> {
Arrays.stream(words).map(word -> new Tuple2<>(word, 1)).forEach(collector::collect);
})
.groupBy(0)
.sum(1)
.print();
}
}
2、使用上面这种写法通常或得到如下错误
Exception in thread "main" org.apache.flink.api.common.functions.InvalidTypesException: The return type of function 'main(FlinkLambdaJob.java:26)' 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.
at org.apache.flink.api.java.DataSet.getType(DataSet.java:178)
at org.apache.flink.api.java.DataSet.flatMap(DataSet.java:266)
at com.huan.study.flink.lambda.FlinkLambdaJob.main(FlinkLambdaJob.java:29)
Caused by: org.apache.flink.api.common.functions.InvalidTypesException: The generic type parameters of 'Collector' are missing. In many cases lambda methods don't provide enough information for automatic type extraction when Java generics are involved. An easy workaround is to use an (anonymous) class instead that implements the 'org.apache.flink.api.common.functions.FlatMapFunction' interface. Otherwise the type has to be specified explicitly using type information.
at org.apache.flink.api.java.typeutils.TypeExtractionUtils.validateLambdaType(TypeExtractionUtils.java:350)
at org.apache.flink.api.java.typeutils.TypeExtractionUtils.extractTypeFromLambda(TypeExtractionUtils.java:176)
at org.apache.flink.api.java.typeutils.TypeExtractor.getUnaryOperatorReturnType(TypeExtractor.java:571)
at org.apache.flink.api.java.typeutils.TypeExtractor.getFlatMapReturnTypes(TypeExtractor.java:196)
at org.apache.flink.api.java.DataSet.flatMap(DataSet.java:266)
at com.huan.study.flink.lambda.FlinkLambdaJob.main(FlinkLambdaJob.java:26)
3、解决方案
默认情况下,flink
可以从方法签名中获取范型
信息,但是 void flatMap(IN value, Collector<OUT> out)
由javac
编译后,会变成 void flatMap(IN value, Collector out)
,导致范型丢失,导致flink
无法自动推断出类型,flink
会认为是Object
类型,从而导致无效的序列化类型。
有了以上认识,我们可以提供如下解决方案
:
1、使用 匿名函数
来替代lambda
表达式
2、从报错信息中,我们知道需要使用 returns
方法来明确的指定返回类型
修改后的代码,此处使用 returns
方法来实现
4、建议
虽然使用 lambda
表达式,在flink
中代码变简洁了,但是需要增加额外的returns
方法来明确的指定返回值类型,因此建议在flink
中尽量少使用lambda
表达式,可以使用匿名类
来代替。不过这也看个人的习惯。