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]类型,然后它应该可以正常工作。