在Spark中导入implicits不起作用

时间:2018-01-18 16:48:39

标签: scala maven apache-spark apache-spark-sql implicit

我正在尝试创建一个特性来将数据从hive表加载到类型化的数据集中。这是代码:

import org.apache.spark.sql.{Dataset, Row, SparkSession}

trait PartitionedHiveTableLoader[T] {
  def context: String
  def table: String
  def returnEntity: Row => T
  def load(sparkSession: SparkSession, token: String): Dataset[T] = {
    import sparkSession.implicits._
    sparkSession.sql(s"SELECT * from $context.$table where d = $token").
      map(returnEntity(_))
  }
  def load(sparkSession: SparkSession, lowBound: String, upperBound: String, includeLow: Boolean = true, includeUpper: Boolean = true): Dataset[T] = {
    import sparkSession.implicits._
    sparkSession.sql(s"SELECT * " +
      s"from $context.$table " +
      s"where d >${if(includeLow)"=" else ""} $lowBound " +
      s"and d<${if(includeUpper)"=" else ""} $upperBound").
      map(returnEntity(_))
  }
}

然后这个特征与Object一起使用如下:

import org.apache.spark.sql.Row

object FreeUsersRightsLoader extends {} with PartitionedHiveTableLoader[FreeUsersRightsEntity] {
  def context: String = "analytics"
  def table: String =  "free_users_rights"
  def returnEntity: Row => FreeUsersRightsEntity = x => FreeUsersRightsDataset(x)
}

但是当我用mvn包编译它时,我有以下错误:

  

错误:无法找到存储在数据集中的类型的编码器。导入spark.implicits.支持原始类型(Int,String等)和产品类型(case类)。将来版本中将添加对序列化其他类型的支持。

但我在每种方法中都引入了spark.implicits ...... 有人知道问题是什么吗?

1 个答案:

答案 0 :(得分:1)

类型Encoder的隐式T必须在编译时可用于您正在使用的方法。

导入import sparkSession.implicits._时,实际上为许多已知常见类型(例如String,Long,Arrays,case classes等)导入了一堆内置编码器,但是 - T 未知未绑定,因此它可能是任何,而且任何类都没有内置编码器 - 因此导入无用。

要解决此问题 - 您应该将隐式编码器参数添加到方法签名中:

def load(sparkSession: SparkSession, token: String)(implicit enc: Encoder[T]): Dataset[T] = {
  sparkSession.sql(s"SELECT * from $context.$table where d = $token").
    map(returnEntity(_))
}

def load(sparkSession: SparkSession,
         lowBound: String,
         upperBound: String,
         includeLow: Boolean = true,
         includeUpper: Boolean = true)(implicit enc: Encoder[T]): Dataset[T] = {
  sparkSession.sql(s"SELECT * " +
    s"from $context.$table " +
    s"where d >${if(includeLow)"=" else ""} $lowBound " +
    s"and d<${if(includeUpper)"=" else ""} $upperBound").
    map(returnEntity(_))
}

然后,只要这些方法被称为,你就需要内置的隐式 - 其中类型T被称为FreeUsersRightsEntity(我假设它是这些中的一个-in类,例如包含基元和集合的案例类):

import spark.implicits._

FreeUsersRightsLoader.load(spark, "token")