如何在DataFrame中定义自定义方法是最佳方式?

13

我需要在DataFrame上定义自定义方法。有什么更好的方法吗?解决方案应具有可扩展性,因为我打算定义大量自定义方法。

我目前的方法是创建一个类(称为MyClass),以DataFrame为参数,定义我的自定义方法(例如customMethod),并定义一个隐式方法将DataFrame转换为MyClass

implicit def dataFrametoMyClass(df: DataFrame): MyClass = new MyClass(df)

因此我可以这样调用:

dataFrame.customMethod()

这样做是正确的吗?欢迎建议。

3个回答

26

你的方法是可行的(参见[1])。尽管我使用了稍微不同的解决方案,但方法仍然相似:

可能性1

隐式

object ExtraDataFrameOperations {
  object implicits {
    implicit def dFWithExtraOperations(df: DataFrame) = DFWithExtraOperations(df)
  }
}

case class DFWithExtraOperations(df: DataFrame) {
  def customMethod(param: String) : DataFrame = {
    // do something fancy with the df
    // or delegate to some implementation
    //
    // here, just as an illustrating example: do a select
    df.select( df(param) )
  }
}

使用方法

要在 DataFrame 上使用新的 customMethod 方法:

import ExtraDataFrameOperations.implicits._
val df = ...
val otherDF = df.customMethod("hello")

可能性2

除了使用上面提到的implicit method,您还可以使用implicit class

隐式类

object ExtraDataFrameOperations {
  implicit class DFWithExtraOperations(df : DataFrame) {
     def customMethod(param: String) : DataFrame = {
      // do something fancy with the df
      // or delegate to some implementation
      //
      // here, just as an illustrating example: do a select
      df.select( df(param) )
    }
  }
}

使用方法

import ExtraDataFrameOperations._
val df = ...
val otherDF = df.customMethod("hello")

备注

如果您想要防止额外的import,请将ExtraDataFrameOperations对象转换为package object并将其存储在您的包中名为package.scala的文件中。

官方文档/参考资料

[1] M. Odersky的原始博客“Pimp my library”可在http://www.artima.com/weblogs/viewpost.jsp?thread=179766找到。


非常感谢您的深入回答!哪种可能性更容易适应能够执行"import spark.implicits._"?前者令人讨厌地需要SparkSession对象,这真是个头疼的问题! - vak

12

有一个稍微简单的方法:只需将MyClass声明为implicit即可。

implicit class MyClass(df: DataFrame) { def myMethod = ... }

这将自动创建隐式转换方法(也称为MyClass)。您还可以通过添加extends AnyVal使其成为值类,从而避免在运行时实际创建MyClass实例,但在实践中这很不可能有什么影响。

最后,将MyClass放入package object中,将允许您在此包的任何位置使用新方法,而无需导入MyClass,这可能对您有利或不利。


非常感谢您提供如此简洁的解决方案!类似于我对马丁的问题:是否有可能调整此解决方案以便能够很好地执行“import spark.implicits._”?前者令人讨厌地需要SparkSession对象,这真是一件头疼的事情! - vak
1
这有什么难的?如果问题是你必须将SparkSession与DataFrame一起传递,那么不用担心,它已经可用了:你可以写import df.sparkSession.implicits._ - Alexey Romanov

0
我认为你应该在DataFrame和你的自定义包装器之间添加一个隐式转换,但是使用一个隐式类 - 这应该是最容易使用的方式,并且你可以将自定义方法存储在一个公共位置。
   implicit class WrappedDataFrame(val df: DataFrame) {
        def customMethod(String arg1, int arg2) {
           ...[do your stuff here]
        }
     ...[other methods you consider useful, getters, setters, whatever]...
      }

如果隐式包装器在DataFrame的范围内,您可以像使用自己的包装器一样使用普通的DataFrame,例如:
df.customMethod("test", 100)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接