Scala:在Spark DataSet上分解filter参数?

时间:2017-07-18 15:51:19

标签: scala apache-spark

我有以下代码,我需要多次输入x._1.x._2.

case class T (Field1: String, Field2: Int, ....)
val j: DataSet[(T, T)] = ...

j.filter(x => x._1.Field1 == x._2.Field1 
  && x._1.Field2 == x._2.Field2
  && ....)

这是一种将x分解为(l, r)的方法,因此表达式可以更短一些吗?

以下内容并不适用于Spark的DataSet。为什么? Spark的DataSet如何不支持Scala的语言构造?

filter{ case (l,r) => ... 

在F#中,您可以编写类似

的内容
j.filter((l, r) -> ....)

甚至

j.filtere(({Field1 = l1; Field2 = l2; ....}, {Field1 = r1; Field2 = r2; ....}) -> ....) 

2 个答案:

答案 0 :(得分:1)

诀窍是使用PartialFunction[A,B]Function1[A,B]的子类的事实,因此,您可以在任何地方使用部分函数语法,预期Function1filtermapflatMap等。):

 j.filter {
    case (l,r) if (l.Field1 == lr.Field1 && l.Field2 == r.Field2 => true
    case _ => false
 }

更新

正如评论中所提到的,遗憾的是这不适用于spark Dataset。这似乎是由于filterDataset中被重载,并且抛出了typer(在scala中通常不鼓励方法重载并且与其他功能不能很好地工作)

解决此问题的方法是定义一个具有不同名称的方法,您可以使用隐式转换在Dataset上进行处理,然后使用该方法代替filter

object PimpedDataset {
  implicit class It[T](val ds: Dataset[T]) extends AnyVal {
   def filtered(f: T => Boolean) = ds.filter(f)
  }
}

...

import PimpedDataset._

j.filtered {
  case (l,r) if (l.Field1 == r.Field1 && l.Field2 == r.Field2 => true
  case _ => false
}

这将编译......

答案 1 :(得分:1)

Spark的Dataset类有多个重载filter(...)方法,编译器无法推断使用哪个方法。你可以明确指定函数类型,但它有点难看。

j.filter({
    case (l, r) => true
}: ((Field1, Field2)) => Boolean)

RDD s仍然可以使用该语法(未明确指定类型)。不幸的是,为了支持Python / R / Etc,Spark开发人员决定放弃那些喜欢编写惯用Scala的用户。 :(