Apache spark 数据帧的动态转换管道

Apache spark 数据帧的动态转换管道,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,是否可以动态构建转换管道并在数据集上执行?假设我有一个数据集ds。我想做一些类似于ds.filter.join.join.filter的事情。现在,管道本身以及过滤器等转换的参数将是动态的(取自用户查询,想象一下描述管道的xml或json) 我觉得编写一些使用纯java反射来实现这一点的东西会很简单。但是,我想知道是否有更好的方法来实现这一点——比如动态构建管道并执行ds.execute(dynamicpeline) 新手火花,并已在互联网/论坛上对此进行了合理搜索。谢谢你的指点。使用Spark

是否可以动态构建转换管道并在数据集上执行?假设我有一个数据集ds。我想做一些类似于ds.filter.join.join.filter的事情。现在,管道本身以及过滤器等转换的参数将是动态的(取自用户查询,想象一下描述管道的xml或json)

我觉得编写一些使用纯java反射来实现这一点的东西会很简单。但是,我想知道是否有更好的方法来实现这一点——比如动态构建管道并执行ds.execute(dynamicpeline)

新手火花,并已在互联网/论坛上对此进行了合理搜索。谢谢你的指点。使用Spark 2+和Java 8。

tl;博士,请不要使用反射。改用Scala语言的库或功能

为了爱这个世界上所有正确的事物,请不要使用反射。编写起来很麻烦,这使得反射代码很容易出错,而且对于所有这些低级工作,您甚至无法获得性能提升。事实上,情况恰恰相反

同时,想要对所有工作进行更高级别的管道编排是很常见的。例如,您可能有一个可用的遗留MapReduce作业,并且希望将输出序列文件馈送给Spark;Spark作业的输出将进入配置单元,在那里可以使用遗留的配置单元查询。等等像这样的开源管道工具也有帮助。级联是另一种,但我认为它还没有Spark支持

但是,如果您喜欢像我一样采取一种方法,最初您更喜欢较轻的解决方案,并且只有在没有这些解决方案的痛苦变得难以忍受时才引入大炮,那么您也许可以利用Scala语言的特性来解决这个问题

我不确定你到底希望做什么,但举例来说,你可能有

trait Foo {
  def sparkSession: SparkSession
  def pipeline: Dataset[Bar] => Dataset[Baz]

  val ds = sparkSession.read(...).as[Bar]
  val dsAfterPipeline = pipeline(ds)
}

class Driver extends App with Foo {
   val sparkSession: SparkSession = ...
   val pipeline: DataSet[Bar] => DataSet[Baz] = ??? //generate pipeline as needed

   dsAfterPipeline.write.parquet("file.parquet")
}
正如您在这里看到的,所有的工作实际上都发生在
Foo
trait中,但该trait要求将其连接到一个类中,该类提供
SparkSession
和一个表示管道的函数。只要它满足
Foo
中规定的合同,就可以按照
Driver
中您认为合适的方式构造它

这种方法将管道代码与编排分离,而且它还使测试更容易,因为您可以提供满足
Dataset[Bar]=>Dataset[Baz]
的任何函数

最后,您可以将此方法与Scala中的
隐式
类相结合(在重新排列了一些东西之后),以丰富(或“pimp”)
数据集
类,从而添加一个
执行
函数,该函数采用管道,但您提供了它:

object Helper {
  implicit class DataSetOps[Bar, Baz](ds: Dataset[Bar]) {
    def execute(pipeline: Dataset[Bar] => Dataset[Baz]) = ???
  }
}
此时您可以执行以下操作:

import Helper._
sparkSession.read(...).as[Bar].execute(pipeline)
其中,
pipeline
再次属于
Dataset[Bar]=>Dataset[Baz]
类型

同样,我不知道您实际上想要做什么,但希望您可以从Scala语言提供的内容或管道库中收集一些想法,以获得所需的内容

最重要的是避免反思