无法找到类型为 org.apache.flink.api.common.typeinfo.TypeInformation[...] 的证据参数的隐式值

30

我正在尝试编写一些关于Apache Flink的用例。我经常遇到一个错误:

could not find implicit value for evidence parameter of type org.apache.flink.api.common.typeinfo.TypeInformation[SomeType]

我的问题是我无法确定它们何时发生,何时不会发生。

最近的一个例子如下:

...
val largeJoinDataGen = new LargeJoinDataGen(dataSetSize, dataGen, hitRatio)
val see = StreamExecutionEnvironment.getExecutionEnvironment
val newStreamInput = see.addSource(largeJoinDataGen)
...

其中LargeJoinDataGen extends GeneratorSource[(Int, String)]GeneratorSource[T] extends SourceFunction[T],它们在不同的文件中定义。

尝试构建时,我得到了以下错误信息:

Error:(22, 39) could not find implicit value for evidence parameter of type org.apache.flink.api.common.typeinfo.TypeInformation[(Int, String)]
val newStreamInput = see.addSource(largeJoinDataGen)

1. 为什么给定的例子会出现错误?

2. 当出现这些错误时,有什么通用指导方针以及如何在未来避免它们?

P.S.: 这是第一个Scala项目和第一个Flink项目,请耐心等待。

4个回答

61

你可以使用导入(import)来替代隐式转换(implicits)

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

它也会有所帮助。


4
这个答案更好,因为它避免了在 Flink 处理程序复杂时多次创建隐式 TypeInformation 的问题 :) - Thomas
为什么它能工作?从一个包中导入所有内容似乎是一种反模式。 - Justin Lin
为什么对我不起作用?我已经使用了 import org.apache.flink.streaming.api.scala._,但仍然出现这个错误。我正在使用 flink 1.12.2。 - Jason Lee
奇怪的是,包对象在1.11.3中看起来与能够工作的一样,而在1.12.3中却不能工作。 - Rajish

18
这通常发生在您有用户代码时,即具有泛型参数的源代码或映射函数等。在大多数情况下,您可以通过添加类似以下内容来修复它:
implicit val typeInfo = TypeInformation.of(classOf[(Int, String)])

如果您的代码位于另一个具有通用参数的方法内,您也可以尝试向该方法的通用参数添加上下文限定符,例如:
def myMethod[T: TypeInformation](input: DataStream[Int]): DataStream[T] = ...

2
这个解决方案似乎可行。方法调用是 TypeInformation.of(classOf[(Int, String)]),你可能需要在你的答案中修复它。 - jheyd

14
我的问题是我无法确定它们何时发生,何时不发生。
当需要一个隐含参数时,它们就会发生。如果我们看一下方法定义,我们会发现:
def addSource[T: TypeInformation](function: SourceFunction[T]): DataStream[T]

但是我们没有看到任何隐式参数定义,它在哪里?
当您看到一个类型参数为形式的多态方法时
def foo[T : M](param: T)

其中T是类型参数,M上下文界定。这意味着方法的创建者正在请求一个类型为M[T]的隐式参数。它等同于:
def foo[T](param: T)(implicit ev: M[T])

在你的方法中,实际上被扩展为:
def addSource[T](function: SourceFunction[T])(implicit evidence: TypeInformation[T]): DataStream[T]

这就是为什么编译器会报错,因为它找不到方法所要求的隐式参数。
如果我们查看Apache Flink Wiki中的Type Information,就可以了解到这种情况的原因:

没有Evidence参数的隐式值错误

在无法创建TypeInformation的情况下,程序会编译失败,并出现一个错误,指出“无法找到类型为TypeInformation的Evidence参数的隐式值”。经常出现这种情况的原因是生成TypeInformation的代码未被导入。确保导入整个flink.api.scala包。 import org.apache.flink.api.scala._

对于泛型方法,您还需要在调用处要求它们生成TypeInformation
对于泛型方法,函数参数和返回类型的数据类型可能不同于每个调用,并且在定义方法的地方是未知的。上面的代码将导致错误,因为没有足够的隐式证据可用。在这种情况下,类型信息必须在调用站点生成并传递给方法。Scala为此提供了隐式参数。
请注意,import org.apache.flink.streaming.api.scala._ 也可能是必要的。
对于您的类型,这意味着如果调用的方法是泛型的,则还需要请求其类型参数的上下文绑定。

1
org.apache.flink.api.scala._已经被导入,但仍然出现问题。这就是我所说的“不能确定”。 - jheyd
1
@jheyd 要求 GeneratorSource[T]SourceFunction[T] 也要有上下文边界:GeneratorSource[T: TypeInformation]SourceFunction[T: TypeInformation] - Yuval Itzchakov
1
SourceFunction是addSource方法所需的Java接口,将上下文边界添加到GeneratorSource并没有改变任何内容。 - jheyd
1
@jheyd 那么也许它需要在更接近的范围内可用。调用flink API的方法是否也是通用的? - Yuval Itzchakov
import org.apache.flink.api.scala._ 对我很有效,非常感谢。 - Cyanny

0
例如 Scala 版本(2.11、2.12 等)不是二进制兼容的。
即使使用 import org.apache.flink.api.scala._,以下配置也是错误的:
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <scala.version>2.12.8</scala.version>
        <scala.binary.version>2.11</scala.binary.version>
    </properties>

Maven中的正确配置:

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <scala.version>2.12.8</scala.version>
        <scala.binary.version>2.12</scala.binary.version>
    </properties>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接