Flink错误:通过字段位置指定密钥仅对元组数据类型有效

时间:2016-07-06 00:53:55

标签: scala apache-flink flink-streaming

我正在使用Flink的Scala API。我对reports = DataStream[Tuple15]进行了一些转换(Tuple15是Scala元组,所有字段都是Int)。问题出在这里:

reports
  .filter(_._1 == 0) // some filter
  .map( x => (x._3, x._4, x._5, x._7, x._8))
      (TypeInformation.of(classOf[(Int,Int,Int,Int,Int)])) // keep only 5 fields as a Tuple5
  .keyBy(2,3,4) // the error is in apply, but I think related to this somehow
  .timeWindow(Time.minutes(5), Time.minutes(1))
  // the line under is line 107, where the error is
  .apply( (tup, timeWindow, iterable, collector: Collector[(Int, Int, Int, Float)]) => {
       ... 
  })

错误说明:

InvalidProgramException: Specifying keys via field positions is only valid for 
tuple data types. Type: GenericType<scala.Tuple5>

整个错误跟踪(我在上面的代码中标记了指向错误的第107行,对应于apply方法):

Exception in thread "main" org.apache.flink.api.common.InvalidProgramException: Specifying keys via field positions is only valid for tuple data types. Type: GenericType<scala.Tuple5>
    at org.apache.flink.api.common.operators.Keys$ExpressionKeys.<init>(Keys.java:217)
    at org.apache.flink.api.common.operators.Keys$ExpressionKeys.<init>(Keys.java:208)
    at org.apache.flink.streaming.api.datastream.DataStream.keyBy(DataStream.java:256)
    at org.apache.flink.streaming.api.scala.DataStream.keyBy(DataStream.scala:289)
here -> at du.tu_berlin.dima.bdapro.flink.linearroad.houcros.LinearRoad$.latestAverageVelocity(LinearRoad.scala:107)
    at du.tu_berlin.dima.bdapro.flink.linearroad.houcros.LinearRoad$.main(LinearRoad.scala:46)
    at du.tu_berlin.dima.bdapro.flink.linearroad.houcros.LinearRoad.main(LinearRoad.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

但这对我没有意义。我使用元组类型,不是吗?或者GenericType<...>的处理方式是什么?

我应该如何修复map以使keyBy工作?

4 个答案:

答案 0 :(得分:2)

原因是TypeInformation属于Java API,因此不知道Scala元组。因此,它返回GenericType,不能用作具有字段位置的keyBy操作的输入。

如果要手动生成Scala元组类型信息,则必须使用createTypeInformation / org.apache.flink.api.scala包对象中包含的org.apache.flink.streaming.api.scala方法。

但是如果导入包对象,则无需手动指定类型信息,因为TypeInformationmap操作的上下文绑定,createTypeInformation是隐函数。

以下代码段显示了处理TypeInformations的惯用方法。

import org.apache.flink.streaming.api.scala._

reports
  .filter(_._1 == 0) // some filter
  .map( x => (x._3, x._4, x._5, x._7, x._8))
  .keyBy(2,3,4) // the error is in apply, but I think related to this somehow
  .timeWindow(Time.minutes(5), Time.minutes(1))
  // the line under is line 107, where the error is
  .apply( (tup, timeWindow, iterable, collector: Collector[(Int, Int, Int, Float)]) => {
       ... 
  })

答案 1 :(得分:1)

好吧,花了很多时间,我实际上只是删除TypeInformation就可以了。所以,改变这个:

.map( x => (x._3, x._4, x._5, x._7, x._8))(TypeInformation.of(classOf[(Int,Int,Int,Int,Int)]))

到此:

.map( x => (x._3, x._4, x._5, x._7, x._8))

尽管如此,我认为这个解决方案有点像黑客,因为我仍然从Flink收到警告(好吧,INFO日志):

00:22:18,662 INFO org.apache.flink.api.java.typeutils.TypeExtractor - class scala.Tuple15 is not a valid POJO type
00:22:19,254 INFO org.apache.flink.api.java.typeutils.TypeExtractor - class scala.Tuple4 is not a valid POJO type

所以,如果有更一般的答案,我会乐意接受它。在那之前,这对我有用。

<强>更新

我之前尝试过这个并且没有工作。我刚刚意识到现在它的工作得益于@Till的回答。那么,以及我所说的内容,您需要导入 org.apache.flink.streaming.api.scala.createTypeInformationorg.apache.flink.api.scala.createTypeInformation不是两者! )。

答案 2 :(得分:1)

我也遇到了同样的问题,并且能够按如下方式修复它:

使用Flink API中的Tuple2类,即 [import org.apache.flink.api.java.tuple.Tuple15] ,而不是 scala.Tuple15

请参阅您的导入部分并进行更正。

这里我使用了 Flink Java API 。如果是 Scala 导入org.apache.flink.api.scala ._

[Apache Flink]

答案 3 :(得分:0)

AggregateOperator仅支持Flink元组。如果您遇到此问题,请首先检查您的导入文件是 scala.Tuple2 ,然后它是错误的。因此应为 org.apache.flink.api.java.tuple.Tuple2