【问题标题】:Load CSV file as dataframe from resources within an Uber Jar从 Uber Jar 中的资源加载 CSV 文件作为数据框
【发布时间】:2020-01-25 20:11:23
【问题描述】:

所以,我制作了一个在 Spark 中运行的 Scala 应用程序,并使用 sbt> 程序集创建了 Uber Jar。

我加载的文件是应用程序需要的查找,因此想法是将它打包在一起。它在 InteliJ 中使用路径“src/main/resources/lookup01.csv”运行良好

我正在 Windows 中进行开发,在本地进行测试,然后将其部署到远程测试服务器。

但是当我在 Windows 机器上调用 spark-submit 时,我得到了错误:

“org.apache.spark.sql.AnalysisException:路径不存在:文件:/H:/dev/Spark/spark-2.4.3-bin-hadoop2.7/bin/src/main/resources/”

似乎它试图在 sparkhome 位置而不是从 JAr 文件中查找文件。

我如何表达路径以便它可以从 JAR 包中查找文件?

我加载数据框的方式的示例代码。加载后,我将其转换为其他结构,如地图。

val v_lookup = sparkSession.read.option( "header", true ).csv( "src/main/resources/lookup01.csv")

我想要实现的是表达路径的方式,以便它可以在我尝试运行 JAR 的每个环境中工作,理想情况下也可以在开发时在 InteliJ 中工作。

编辑:scala 版本是 2.11.12

更新:

似乎要处理 JAR 中的文件,我必须将其作为流读取,下面的代码有效,但我无法找到一种安全的方法来提取文件的标题,例如 SparkSession.read .option 有。

val fileStream = scala.io.Source.getClass.getResourceAsStream("/lookup01.csv")
val inputDF = sparkSession.sparkContext.makeRDD(scala.io.Source.fromInputStream(fileStream).getLines().toList).toDF

应用 makeRDD 后,我得到了 RDD,然后可以将其转换为数据帧,但似乎我失去了使用“读取”选项将标头解析为架构的能力。

使用 makeRDD 有什么办法吗?

另一个问题是,我似乎必须手动将行解析成列。

【问题讨论】:

    标签: scala apache-spark jar


    【解决方案1】:

    你必须从classPath获取正确的路径

    考虑到你的文件在 src/main/resources 下:

    val path = getClass.getResource("/lookup01.csv")
    
    val v_lookup = sparkSession.read.option( "header", true ).csv(path)
    

    【讨论】:

    • 您好,我尝试了您的解决方案,现在似乎可以查看 JAR 内部,但找不到文件:org.apache.spark.sql.AnalysisException:路径不存在:文件:/C: /Users/ac/IdeaProjects/apptest/target/scala-2.11/apptest-assembly-0.1.jar!/lookup01.csv;我打开了 JAR,文件在根目录下。
    • 文件是在 src/main/resources 根目录下还是其他文件夹下?
    • 是的,文件在 /src/main/resources 文件夹下
    • 你能打开jar并检查.csv文件是否在resources文件夹下吗?我只是猜测该文件没有被复制您在项目中使用 maven 吗?如果是这样,您可以查看此链接baeldung.com/executable-jar-with-maven
    • JAR 中似乎不存在 ressources 文件夹,IDE 中 ressources 文件夹中的文件最终位于 JAR 文件的根目录中。我不认为它是一个 Maven 项目,它是作为 Scala SBT 项目创建的
    【解决方案2】:

    所以,这一切都表明,文件在JAR中后,只能作为输入流访问,以从压缩文件中读取数据块。

    我找到了一个解决方案,尽管它并不漂亮,但它可以满足我的需要,即读取 csv 文件,获取前 2 列并将其放入数据框,然后将其加载到键值结构中(在这种情况下,我创建了一个案例类来保存这些对)。

    我正在考虑将这些查找迁移到 HOCON 文件,这可能会减少加载这些查找的过程的复杂性

    
    import sparkSession.implicits._
    val fileStream = scala.io.Source.getClass.getResourceAsStream("/lookup01.csv")
    val input = sparkSession.sparkContext.makeRDD(scala.io.Source.fromInputStream(fileStream).getLines().toList).toDF()
    
    val myRdd = input.map {
          line =>
            val col = utils.Utils.splitCSVString(line.getString(0))
            KeyValue(col(0), col(1))
        }
    
    val myDF = myRdd.rdd.map(x => (x.key, x.value)).collectAsMap()
    
    fileStream.close()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-11
      • 1970-01-01
      • 2012-03-10
      • 1970-01-01
      • 2015-11-16
      • 2015-05-03
      • 1970-01-01
      相关资源
      最近更新 更多