2016-03-28 35 views
2

我正在为我的Scala Spark应用程序编写一些单元测试 为了做到这一点,我需要在测试中创建不同的数据框。所以我写了一个非常短的DFsBuilder代码,基本上允许我添加新行并最终创建DF。该代码是:在导入sqlContext暗含之后Spark toD无法解析符号

class DFsBuilder[T](private val sqlContext: SQLContext, private val columnNames: Array[String]) { 
    var rows = new ListBuffer[T]() 

    def add(row: T): DFsBuilder[T] = { 
    rows += row 
    this 
    } 

    def build() : DataFrame = { 
    import sqlContext.implicits._ 
    rows.toList.toDF(columnNames:_*) // UPDATE: added :_* because it was accidently removed in the original question 
    } 
} 

然而toDF方法不能与编译无法解析符号toDF。

因为我需要创建不同种类的DF(不同数量的列和不同的列类型),所以我编写了此泛型编译器代码。我想使用它的方式是在单元测试中定义一些特定的案例类别,并将其用于构建器

我知道这个问题与某些事实有关,我使用的是泛型(可能是某种类型的删除的问题),但我不能完全把我的手指上的问题是,究竟是什么

所以我的问题是:

  • 谁能告诉我问题出在哪里?并希望如何解决这个问题
  • 如果这个问题不能以这种方式解决,有人可能会提供另一种优雅的方式来创建数据框? (我不喜欢污染与创建代码我的单元测试)

我明明先用Google搜索这个问题,但只找到例子,人们忘了进口约的情况下,类sqlContext.implicits方法或一些东西的范围由可能还不如我在提前

回答

1

谢谢如果你看看toDF签名和SQLImplicits.localSeqToDataFrameHolder(这是所使用的隐函数),你就可以发现两个问题同样的问题:

  1. 类型T必须是Product(所有案例类,元组的超类)的子类,并且您必须为其提供隐含的TypeTag。为了解决这个问题 - 改变你的类的声明:

    class DFsBuilder[T <: Product : TypeTag](...) { ... } 
    
  2. columnNames参数是Array类型不,这是一个“重复参数”(如Java的“可变参数”,参见4.6.2 here)所以你必须给数组转换成参数:

    rows.toList.toDF(columnNames: _*) 
    

有了这两个变化,你的代码编译(和作品)。

+0

其实columnName是用于你在第二个项目符号中显示的,我可能会意外地将它删除了。我为此道歉。扩展产品和类型标签确实有用!非常感谢:) – Gideon

+1

只需添加TypeTag应该导入使用:'import scala.reflect.runtime.universe.TypeTag'因为显然Java也有TypeTag类 – Gideon