【问题标题】:Interoperability : sharing Datasets of objects or Row between Java and Scala, two ways. I put a Scala dataset operation in the middle of Java ones互操作性:在 Java 和 Scala 之间共享对象或 Row 的数据集,两种方式。我将 Scala 数据集操作放在 Java 数据集的中间
【发布时间】:2020-09-22 19:28:12
【问题描述】:

目前,我的主应用程序是用 Java Spring-boot 构建的,这不会改变,因为它很方便。
@Autowired 服务 bean 实现,用于示例:

  • 企业企业数据集。第一个还能够返回一个 Enterprise 对象的列表,这些对象具有Map 的机构。
    所以服务返回:Dataset<Enterprise>Dataset<Establishment>Dataset<Row>
  • 协会:Dataset<Row>
  • 城市:Dataset<Commune>Dataset<Row>
  • 地方当局:Datatset<Row>.

许多用户案例函数都是这种调用:

什么是关联(年=2020)?

我的应用程序转发给datasetAssociation(2020),它与企业和机构数据集以及城市和地方当局的数据集一起操作,以提供有用的结果。

许多人建议我从 Scala 能力中受益

为此,我正在考虑在数据集之间进行涉及其他操作的操作:

  • 一些由 Row 制成,
  • 一些搬运混凝土物体。

就达到/涉及的数据集而言,我有这个操作要做:
协会。enterprises.establishments.cities.localautorities

我能在 Scala 中写粗体部分吗?这意味着:

  1. 使用 Java 代码构建的Dataset<Row> 被发送到 Scala 函数以完成。

  2. Scala 使用 EnterpriseEstablishment 对象创建一个新数据集。
    a) 如果对象的源代码是用 Scala 编写的 我不必在 Java 中为它重新创建新的源。
    b) 相反,如果对象的源是用 编写的>Java,我不必在 Scala 中重新创建新的源代码。
    c) 我可以使用 Scala 此数据集在 Java 端直接返回的对象。

  3. Scala 将不得不调用在 Java 中实现的函数,并向它们发送它正在创建的底层数据集(例如,用城市信息完成它们)。

Java 随时调用 Scala 方法
Scala 也随时调用 Java 方法:

一个操作可以跟随a
Java -> Scala -> Scala -> Java -> Scala -> Java -> Java
路径,如果需要,就调用方法的母语而言。
因为我事先不知道哪些部分对移植到 Scala 有用。

完成这三点后,我会认为 JavaScala 能够以两种方式互操作并相互受益。

但是我可以实现这个目标吗(在Spark 2.4.x 或更可能在Spark 3.0.0)?

总结一下,是Java和Scala互操作的两种方式,一种方式是:

  • 它不会使源代码的一侧或另一侧过于笨拙。或者最坏的情况:重复。
  • 它不会严重降低性能(例如,必须重新创建整个数据集或转换其中包含的每个对象,无论是一侧还是另一侧,都会令人望而却步)。

【问题讨论】:

  • 除了Java -> Scala -> Scala -> Java -> Scala -> Java -> Java 是否可行之外,目前尚不清楚您的问题是什么。考虑修改?
  • 我想将部分操作从 Java 移植到 Scala。假设该操作涉及数据集 ABCD。我可能希望只移植数据集 C,例如在 Scala 中。然后 A 数据集(使用 Java 创建的)将加入或使用 B 的结果也使用 Java 创建,也可以使用 C,使用 ScalaScala 程序创建它也必须调用 Java获取 D 数据集的函数。 JavaScala 语言将混合使用。总体问题是:“真的有可能吗?
  • 我在Java -> Scala -> Java -> Scala 之前使用过这个互操作链,因此您期望使用的互操作链可以正常工作。
  • 目前我不知道如何直接在 Java 中使用在 Scala 中创建的具体对象的数据集,而不通过 Parquet 存储来传输例如,使用第二个源文件在 Java 中设置和重新创建类似的对象。这就是我问的原因。

标签: java scala apache-spark scala-java-interop


【解决方案1】:

正如 Jasper-M 所写,scala 和 java 代码完全可以互操作:

  • 它们都编译成 jvm 以相同方式执行的 .class 文件
  • spark java 和 scala API 一起工作,有几个细节:
    • 两者都使用相同的 Dataset 类,所以没有问题
    • 但是,SparkContext 和 RDD(以及所有 RDD 变体)具有在 java 中不实用的 scala api。主要是因为 scala 方法将 scala 类型作为输入,而不是您在 java 中使用的那些。但是它们都有Java包装器(JavaSparkContext,JavaRDD)。用 java 编码,你可能已经看过那些包装器了。

现在,正如许多人所建议的,spark 首先是一个 scala 库,而且 scala 语言比 java (*) 更强大,使用 scala 编写 spark 代码会容易得多。此外,您会在 scala 中找到更多代码示例。通常很难找到用于复杂数据集操作的 java 代码示例。

所以,我认为您应该注意的两个主要问题是:

  1. (与 spark 无关,但必要)有一个项目可以编译两种语言并允许双向互操作性。我认为 sbt 提供了开箱即用的功能,并且使用 maven,您需要使用 scala 插件,并且(根据我的经验)将 java 和 scala 文件都放在 java 文件夹中。否则一个可以调用另一个,但不能相反(scala调用java但java不能调用scala,或者相反)
  2. 您应该小心每次创建类型化数据集时使用的编码器(即Dataset[YourClass] 而不是Dataset<Row>)。在 Java 中,对于 java 模型类,您需要显式使用 Encoders.bean(YourClass.class)。但是在 scala 中,默认情况下 spark 隐式查找编码器,并且编码器是为 scala 案例类(“产品类型”)和 scala 标准集合构建的。因此,请注意使用了哪些编码器。例如,如果您在 scala 中创建 YourJavaClass 的数据集,我认为您可能必须明确给出 Encoders.bean(YourJavaClass.class) 才能使其工作并且不会出现序列化问题。

最后一点:您写道您使用 java Spring-boot。所以

  • 请注意,Spring 设计完全违背了 scala/功能推荐的做法。到处使用 null 和 mutable 的东西。你仍然可以使用 Spring,但在 scala 中可能会很奇怪,社区可能不会轻易接受它。
  • 你可以从spring上下文中调用spark代码,但不应该使用spark中的spring(上下文),尤其是在spark分发的方法内部,比如rdd.map。这将尝试在每个工作人员中创建 Spring 上下文,这非常慢并且很容易失败。

(*) 关于“scala 比 java 更强大”:我并不是说 scala 比 java 更好(我确实这么认为,但这是一个品味问题 :)。我的意思是 scala 语言提供了比 java 更多的表现力。基本上它用更少的代码做更多的事情。主要区别在于:

  • 隐式,被 spark api 大量使用
  • monad + 理解
  • 当然还有强大的类型系统(例如,阅读协变类型,List[Dog] 是 scala 中 List[Animal] 的子类,但在 java 中不是)

【讨论】:

  • 感谢您的安慰。我接受了。
  • 我使用 scala 和 spark 工作了 4 年,我真的很喜欢它。现在我又回到了 java+spring 项目。已经有些痛苦了。但我开始了解这两个世界。
  • 如果我遇到与我所描述的内容相关的问题,我会在这里打开一个答案。
【解决方案2】:

是的,这可能不会导致性能下降或额外代码过于笨拙。 Scala 和 Java 几乎可以完美地互操作,而且 Spark Dataset API 在 Java 和 Scala 之间共享。无论您使用 Java 还是 Scala,Dataset 类都是完全相同的。正如您在javadocscaladoc 中看到的(注意它们只是布局不同,内容不同)Java 和Scala 代码完全可以互换。最多Scala代码会更简洁一些。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多