是否可以动态构建转换管道并在数据集上执行?想象一下,我有一个数据集ds。我想做像ds.filter.join.join.filter这样的事情。现在,管道本身和转换的参数(如过滤器等)将是动态的(取自用户查询,想象一个描述管道的xml或json)。
我觉得编写一些使用普通java反射的东西会很简单。但是,我想知道是否有更好的方法来执行此操作 - 例如动态构建管道并执行ds.execute(dynamicPipeline)。
新手激发并在互联网/论坛上合理搜索此事。任何指针都赞赏。使用Spark 2+和Java 8。
答案 0 :(得分:0)
tl; dr 请不要使用反射。请改用库或Scala语言的功能。
为了对世界上所有人的爱,请不要使用反思。写入很麻烦,这使得反射代码容易出错,对于所有低级别的工作,你甚至不会获得性能提升。事实上,情况正好相反。
与此同时,想要更高级别的管道编排工作是相当普遍的。例如,您可能有一个有效的遗留MapReduce作业,并且您希望将输出序列文件提供给Spark;您的Spark作业的输出转到Hive,在那里您可以使用传统的Hive查询。等等。有像Oozie这样的开源管道工具可以提供帮助。级联是另一个,但我不相信它有Spark支持。
然而,如果你喜欢采用Suffering-Oriented Programming方法,而你最初喜欢较轻的解决方案,只有在没有它们的痛苦变得太大而无法承受的情况下才会带上大枪,那么也许你可以利用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
特征中,但该特征要求将其连接到提供SparkSession
和的类中表示管道的函数。只要符合Driver
中指定的合同,就可以在Foo
中看到它。{/ p>
这种方法将管道代码与业务流程分离,并且它还使测试更容易,因为您可以提供满足Dataset[Bar] => Dataset[Baz]
的任何函数。
最后,您可以将此方法与Scala中的implicit
类(重新排列一些内容)结合起来,以丰富(或#34; pimp")DataSet
类来添加{ {1}}接受管道的功能,但是你提供它:
execute
此时你可以这样做:
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
。
同样,我不知道你真正想做什么,但希望你可以从Scala语言提供的内容或管道库中收集一些想法以获得你需要的东西。
最重要的是避免反思。