Каков наилучший способ определения пользовательских методов в DataFrame?
Мне нужно определить пользовательские методы на DataFrame. Какой лучший способ сделать это? Решение должно быть масштабируемым, так как я намерен определить значительное количество пользовательских методов.
Мой текущий подход заключается в создании класса (скажем, MyClass
) с DataFrame
в качестве параметра определите мой пользовательский метод (скажем, customMethod
) в этом и определить неявный метод, который преобразует DataFrame
в MyClass
,
implicit def dataFrametoMyClass(df: DataFrame): MyClass = new MyClass(df)
Таким образом я могу позвонить:
dataFrame.customMethod()
Это правильный способ сделать это? Открыт для предложений.
3 ответа
Твой путь - это путь (см. [1]). Хотя я решил это немного по-другому, подход остается схожим:
Возможность 1
Implicits
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) )
}
}
использование
Чтобы использовать новый customMethod
метод на DataFrame
:
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
, повернуть object
ExtraDataFrameOperations
в package object
и сохранить его в файле с именем package.scala
в вашем пакете.
Официальная документация / ссылки
[1] Оригинальный блог М.Одерского "Прокачай мою библиотеку" доступен по адресу http://www.artima.com/weblogs/viewpost.jsp?thread=179766
Есть немного более простой подход: просто объявите MyClass
какimplicit
implicit class MyClass(df: DataFrame) { def myMethod = ... }
Это автоматически создает метод неявного преобразования (также называетсяMyClass
). Вы также можете сделать его классом стоимости, добавивextends AnyVal
который избегает некоторых накладных расходов, фактически не создаваяMyClass
Например, во время выполнения, но это вряд ли имеет значение на практике.
Наконец, положитьMyClass
вpackage object
позволит вам использовать новые методы в любом месте этого пакета, не требуя импорта MyClass
, что может быть выгодой или недостатком для вас.
Я думаю, что вам следует добавить неявное преобразование между 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("тест", 100)