使用Scala 2.11的Spark 2.3.0。我根据文档here实施了自定义Aggregator
。聚合器需要3种类型的输入,缓冲和输出。
我的聚合器必须对窗口中的所有先前行进行操作,因此我将其声明为:
case class Foo(...)
object MyAggregator extends Aggregator[Foo, ListBuffer[Foo], Boolean] {
// other override methods
override def bufferEncoder: Encoder[ListBuffer[Mod]] = ???
}
其中一个覆盖方法应该返回缓冲区类型的编码器,在本例中为ListBuffer
。我无法为org.apache.spark.sql.Encoders
找到任何合适的编码器,也没有任何其他编码方式,所以我不知道该返回什么。
我想创建一个新的case类,它有一个ListBuffer[Foo]
类型的单一属性,并将其用作我的缓冲类,然后使用Encoders.product
,但我不确定是否是必要的,或者如果还有别的东西,我会失踪。感谢您的任何提示。
答案 0 :(得分:4)
您应该让Spark SQL完成其工作并使用append()
找到正确的编码器,如下所示:
ExpressionEncoder
答案 1 :(得分:1)
我在org.apache.spark.sql.Encoders中看不到任何可用于直接编码ListBuffer的东西,或者甚至是List
如你所建议的那样,将一个选项放在案例类中似乎是一个选择:
import org.apache.spark.sql.Encoders
case class Foo(field: String)
case class Wrapper(lb: scala.collection.mutable.ListBuffer[Foo])
Encoders.product[Wrapper]
另一种选择可能是使用kryo:
Encoders.kryo[scala.collection.mutable.ListBuffer[Foo]]
或者最后你可以看一下ExpressionEncoders,它扩展了Encoder:
import org.apache.spark.sql.catalyst.encoders.ExpressionEncoder
ExpressionEncoder[scala.collection.mutable.ListBuffer[Foo]]
这是最好的解决方案,因为它可以使一切对催化剂透明,因此可以进行所有精彩的优化。
在玩游戏时我注意到了一件事:
ExpressionEncoder[scala.collection.mutable.ListBuffer[Foo]].schema == ExpressionEncoder[List[Foo]].schema
我在执行聚合时没有测试过上述任何内容,因此可能存在运行时问题。希望这有用。