Scala:如何将任何泛型序列作为此方法的输入
我是斯卡拉·努布。还在努力学习语法 我试图减少将测试数据转换为数据帧所需编写的代码。以下是我现在拥有的:Scala:如何将任何泛型序列作为此方法的输入,scala,apache-spark,dataframe,apache-spark-sql,Scala,Apache Spark,Dataframe,Apache Spark Sql,我是斯卡拉·努布。还在努力学习语法 我试图减少将测试数据转换为数据帧所需编写的代码。以下是我现在拥有的: def makeDf[T](seq: Seq[(Int, Int)], colNames: String*): Dataset[Row] = { val context = session.sqlContext import context.implicits._ seq.toDF(colNames: _*) } 问题在于,上述方法仅将形状Seq[(Int,
def makeDf[T](seq: Seq[(Int, Int)], colNames: String*): Dataset[Row] = {
val context = session.sqlContext
import context.implicits._
seq.toDF(colNames: _*)
}
问题在于,上述方法仅将形状Seq[(Int,Int)]
的序列作为输入。如何使其接受任何序列作为输入?我可以将输入形状更改为Seq[AnyRef]
,但是代码无法将toDF
调用识别为有效符号
我不知道该怎么做。有什么想法吗?谢谢 简短回答:
import scala.reflect.runtime.universe.TypeTag
def makeDf[T <: Product: TypeTag](seq: Seq[T], colNames: String*): DataFrame = ...
这反过来又需要生成一个编码器。问题是编码器只在某些类型上定义。特别是产品(如元组、case类等),您还需要添加类型标签隐式,以便Scala能够克服类型擦除(在运行时,所有序列都具有类型序列,而不管泛型类型如何。类型标签提供了这方面的信息)
作为侧节点,您不需要从会话中提取sqlcontext,只需使用:
import sparkSession.implicits._
简短答复:
import scala.reflect.runtime.universe.TypeTag
def makeDf[T <: Product: TypeTag](seq: Seq[T], colNames: String*): DataFrame = ...
这反过来又需要生成一个编码器。问题是编码器只在某些类型上定义。特别是产品(如元组、case类等),您还需要添加类型标签隐式,以便Scala能够克服类型擦除(在运行时,所有序列都具有类型序列,而不管泛型类型如何。类型标签提供了这方面的信息)
作为侧节点,您不需要从会话中提取sqlcontext,只需使用:
import sparkSession.implicits._
正如@AssafMendelson已经解释的,为什么不能创建
任何的数据集
的真正原因是Spark需要编码器
将对象从JVM表示转换为其内部表示,而Spark不能保证生成这种编码器
用于任何类型
阿萨夫的回答是正确的,并且会起作用。
然而,依我看,它限制太多,因为它只适用于产品
(元组和用例类)-即使这包括大多数用例,也有少数用例被排除在外
由于您真正需要的是一个编码器
,因此您可以将此责任留给客户。在大多数情况下,只需调用import spark.implicits.\u
即可将它们放入范围。
因此,我认为这将是最普遍的解决办法
import org.apache.spark.sql.{DataFrame, Dataset, Encoder, SparkSession}
// Implicit SparkSession to make the call to further methods more transparent.
implicit val spark = SparkSession.builder.master("local[*]").getOrCreate()
import spark.implicits._
def makeDf[T: Encoder](seq: Seq[T], colNames: String*)
(implicit spark: SparkSession): DataFrame =
spark.createDataset(seq).toDF(colNames: _*)
def makeDS[T: Encoder](seq: Seq[T])
(implicit spark: SparkSession): Dataset[T] =
spark.createDataset(seq)
注意:这基本上是从Spark重新发明了已经定义好的函数。正如@AssafMendelson已经解释的那样,无法创建任何的数据集的真正原因是因为Spark需要一个编码器来转换JVM中的对象对其内部表示的表示-和Spark不能保证为任何类型生成此类编码器
阿萨夫的回答是正确的,并且会起作用。
然而,依我看,它限制太多,因为它只适用于产品
(元组和用例类)-即使这包括大多数用例,也有少数用例被排除在外
由于您真正需要的是一个编码器
,因此您可以将此责任留给客户。在大多数情况下,只需调用import spark.implicits.\u
即可将它们放入范围。
因此,我认为这将是最普遍的解决办法
import org.apache.spark.sql.{DataFrame, Dataset, Encoder, SparkSession}
// Implicit SparkSession to make the call to further methods more transparent.
implicit val spark = SparkSession.builder.master("local[*]").getOrCreate()
import spark.implicits._
def makeDf[T: Encoder](seq: Seq[T], colNames: String*)
(implicit spark: SparkSession): DataFrame =
spark.createDataset(seq).toDF(colNames: _*)
def makeDS[T: Encoder](seq: Seq[T])
(implicit spark: SparkSession): Dataset[T] =
spark.createDataset(seq)
注意:这基本上是从Spark中重新创建已定义的函数。据我所知,Spark不支持udf()s中的AnyRef。正如我所见,您使用了泛型类型t,但没有使用它,而toDF方法在seq上,所以您可以做的是将其设置为seq[t]类型,然后它应该可以正常工作。据我所知,Spark不支持udf()s中的AnyRef。正如我所看到的,您使用了泛型类型t,但没有使用它,并且toDF方法位于seq上,所以您可以将其设置为seq[t]类型,然后它应该可以正常工作。