Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何为Scala集合创建编码器(实现自定义聚合器)?_Scala_Apache Spark_Apache Spark Sql_Apache Spark Encoders - Fatal编程技术网

如何为Scala集合创建编码器(实现自定义聚合器)?

如何为Scala集合创建编码器(实现自定义聚合器)?,scala,apache-spark,apache-spark-sql,apache-spark-encoders,Scala,Apache Spark,Apache Spark Sql,Apache Spark Encoders,Spark 2.3.0和Scala 2.11。我正在根据文档实现一个定制的聚合器。聚合器需要输入、缓冲区和输出三种类型 我的聚合器必须作用于窗口中所有前面的行,因此我声明如下: case class Foo(...) object MyAggregator extends Aggregator[Foo, ListBuffer[Foo], Boolean] { // other override methods override def bufferEncoder: Encode

Spark 2.3.0和Scala 2.11。我正在根据文档实现一个定制的
聚合器。聚合器需要输入、缓冲区和输出三种类型

我的聚合器必须作用于窗口中所有前面的行,因此我声明如下:

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
,但我不确定这是否是必要的,或者我是否还缺少其他东西。感谢您提供的任何提示。

我在org.apache.spark.sql.Encoders中看不到任何可以用于直接编码ListBuffer的内容,或者甚至是列表

正如您所建议的,将其放入案例类似乎是一种选择:

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,它扩展了编码器:

import org.apache.spark.sql.catalyst.encoders.ExpressionEncoder
ExpressionEncoder[scala.collection.mutable.ListBuffer[Foo]]
这是最好的解决方案,因为它使一切对catalyst透明,因此允许catalyst进行所有精彩的优化

我在看戏时注意到一件事:

ExpressionEncoder[scala.collection.mutable.ListBuffer[Foo]].schema == ExpressionEncoder[List[Foo]].schema

我在执行聚合时没有测试上述任何一项,因此可能存在运行时问题。希望这会有所帮助。

您应该让Spark SQL完成它的工作,并使用
ExpressionEncoder
找到合适的编码器,如下所示:

scala> spark.version
res0: String = 2.3.0

case class Mod(id: Long)

import org.apache.spark.sql.Encoder
import scala.collection.mutable.ListBuffer
import org.apache.spark.sql.catalyst.encoders.ExpressionEncoder

scala> val enc: Encoder[ListBuffer[Mod]] = ExpressionEncoder()
enc: org.apache.spark.sql.Encoder[scala.collection.mutable.ListBuffer[Mod]] = class[value[0]: array<struct<id:bigint>>]
scala>spark.version
res0:String=2.3.0
案例类别模块(id:Long)
导入org.apache.spark.sql.Encoder
导入scala.collection.mutable.ListBuffer
导入org.apache.spark.sql.catalyst.encoders.ExpressionEncoder
scala>val enc:Encoder[ListBuffer[Mod]]=ExpressionEncoder()
enc:org.apache.spark.sql.Encoder[scala.collection.mutable.ListBuffer[Mod]]=class[value[0]:数组]

只是分析你所说的,以便更好地理解事情。“我的聚合器必须作用于窗口中的所有前几行,所以我这样声明:“聚合器作用于前几行还是任何行有什么区别吗?”?好奇这有多重要。在我的用例中,假设有5行,第1行的结果取决于第1行,第2行的结果取决于第1行和第2行,第3行的结果取决于第1-3行,以此类推。这取决于特定的行排序。如果每一行都依赖于所有其他行,我想我必须在两个过程中完成这项工作,首先使用collect\u list或collect\u set收集窗口的所有值,然后通过另一个过程计算聚合值。这不是窗口聚合和“前几行”的要求吗一个窗口规范?谢谢你,它非常简单,看起来很有效。隐式创建的编码器不是我可以显式创建的编码器。