Последствия Spark, не разрешающиеся внутри области видимости

#scala #apache-spark #implicit

#scala #apache-spark #неявный

Вопрос:

У меня есть некоторый код scala / spark, который выглядит следующим образом:

   import sqlContext.implicits._

  val join: (Dataset[MyCaseClassA], Dataset[MyCaseClassB]) => Dataset[AB] = (a, b) =>
    a.joinWith(b,
      a("prop_a1") === b("prob_b1"),
      "left"
    ) //more code...
  

Это отлично работает и компилируется и все такое. Но, допустим, я хочу заняться некоторым функциональным программированием, поэтому я реорганизовал все это, чтобы:

   import sqlContext.implicits._

  val join: (Unit => Dataset[MyCaseClassA], Unit => Dataset[MyCaseClassB]) => Dataset[AB] = (a, b) =>
     a(Unit).joinWith(b(Unit),
        a("prop_a1") === b("prob_b1"),
        "left"
     ) //more code...
  

AFAIKT это должно работать просто отлично. Однако в конечном итоге происходит то, что IntelliJ сразу становится серым import sqlContext.implicits._ , и методы === перестают разрешаться с помощью value === is not a member of org.apache.spark.sql.Dataset .

Поэтому по какой-то причине import sqlContext.implicits._ просто не работает при передаче функциональных аргументов. Мои вопросы:

  1. Почему неявный импорт перестает работать?
  2. Что я могу сделать, чтобы импорт работал и по-прежнему использовал аргументы функции?

Ответ №1:

В основном дело не в последствиях, а в несоответствии типов (а последствия очень чувствительны к типам).

Unit в a(Unit) , b(Unit) является сопутствующим объектом абстрактного класса Unit . У него нет типа Unit (у него есть тип Unit.type ). Это () то, что имеет тип Unit .

a(Unit) , b(Unit) компилируйте только потому, что в Scala любой тип (например Unit.type ) может быть преобразован в Unit .

Также вы не можете писать a("prop_a1") , b("prob_b1") потому что a b это функции из Unit , к которым вы не можете применить String .

Итак, хотя

 val join: (Unit => Dataset[MyCaseClassA], Unit => Dataset[MyCaseClassB]) => Dataset[AB] = (a, b) =>
  a(Unit).joinWith(b(Unit),
    a(Unit)("prop_a1") === b(Unit)("prob_b1"),
    "left"
  ) //more code...
  

скомпилировать (аналогично даже

 val join: (Unit => Dataset[MyCaseClassA], Unit => Dataset[MyCaseClassB]) => Dataset[AB] = (a, b) =>
  a(1).joinWith(b("A"),
    a(true)("prop_a1") === b(???)("prob_b1"),
    "left"
  ) //more code...
  

будет компилироваться) кажется, вы на самом деле имели в виду

 val join: (Unit => Dataset[MyCaseClassA], Unit => Dataset[MyCaseClassB]) => Dataset[AB] = (a, b) =>
  a(()).joinWith(b(()),
    a(())("prop_a1") === b(())("prob_b1"),
    "left"
  ) //more code...
  

Также немного странно принимать, Unit обычно Unit возвращается.

Вы могли бы написать

 val join: (() => Dataset[MyCaseClassA], () => Dataset[MyCaseClassB]) => Dataset[AB] = (a, b) =>
  a().joinWith(b(),
    a()("prop_a1") === b()("prob_b1"),
    "left"
  ) //more code...
  

Здесь () => ... он же Function0[...] — это тип функций без аргументов.

Или вы можете писать с аргументами по имени

 val join: (=> Dataset[MyCaseClassA], => Dataset[MyCaseClassB]) => Dataset[AB] = (a, b) =>
  a.joinWith(b,
    a("prop_a1") === b("prob_b1"),
    "left"
  ) //more code...