【问题标题】:Reading CSV files contains struct type in Spark using Java使用 Java 读取 CSV 文件包含 Spark 中的结构类型
【发布时间】:2020-02-07 21:07:33
【问题描述】:

我正在尝试为程序编写测试用例。 为此,我正在读取包含以下格式数据的 CSV 文件。
account_number,struct_data 123456789,{"key1":"value","key2":"value2","keyn":"valuen"} 987678909,{"key1":"value0","key2":"value20","keyn":"valuen0"}
数百个这样的行。

我需要将第二列作为结构读取。但我得到了错误 struct type expected, string type found

我尝试转换为 StructType,然后得到错误为“StringType 无法转换为 StructType”。

我应该改变我的 CSV 的方式吗?我还能做什么?

【问题讨论】:

  • csv 文件中的所有结构值是否都包含相同的架构?
  • 我会改写:struct_data 字段的架构对于所有记录都相同吗?例如,它们是否具有相同且相同数量的键:key1key2 等...
  • @TravisHegner 是的,struct_data 字段的架构是相同的。
  • 您所做的编辑表明它相同。如果你所有的 json 字符串都有相同的键,那么你可以使用from_json()spark 函数将其转换为结构类型,但如果键不一样,那将不起作用。
  • @Travis 我的错,我改了。 Json 部分确实具有相同的架构。你能详细说明你想说什么吗?

标签: java apache-spark hadoop apache-spark-sql


【解决方案1】:

我在 Scala Spark 中提供了我的解决方案,它可能会为您的查询提供一些见解

scala> val sdf = """{"df":[{"actNum": "1234123", "strType": [{"key1": "value1", "key2": "value2"}]}]}"""
sdf: String = {"df":[{"actNum": "1234123", "strType": [{"key1": "value1", "key2": "value2"}]}]}

scala> val erdf = spark.read.json(Seq(sdf).toDS).toDF().withColumn("arr", explode($"df")).select("arr.*")
erdf: org.apache.spark.sql.DataFrame = [actNum: string, strType: array<struct<key1:string,key2:string>>]

scala> erdf.show()
+-------+-----------------+
| actNum|          strType|
+-------+-----------------+
|1234123|[[value1,value2]]|
+-------+-----------------+


scala> erdf.printSchema
root
 |-- actNum: string (nullable = true)
 |-- strType: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- key1: string (nullable = true)
 |    |    |-- key2: string (nullable = true)

【讨论】:

  • 您正在创建一个字符串?以 Json 格式?,但是,我在两列中都有很多这样的行。
  • 出于测试目的并假设它是一次性活动,您可以将 csv 转换为 json 并与它一起使用
  • 我同意,但是我可以使用我之前的数据集(字符串,字符串)将整个转换为json格式,而不是完整地编写吗?你能帮我吗?
  • 你能成功读取数据吗??我假设您可以阅读但不能分配数据类型。
  • 是的,我可以读取数据,但在将其转换为结构类型时遇到了困难。
【解决方案2】:

如果所有 json 记录具有相同的架构,您可以定义它并使用 sparks from_json() 函数来完成您的任务。

import org.apache.spark.sql.types.StructType

val df = Seq(
    (123456789, "{\"key1\":\"value\",\"key2\":\"value2\",\"keyn\":\"valuen\"}"),
    (987678909, "{\"key1\":\"value0\",\"key2\":\"value20\",\"keyn\":\"valuen0\"}")
    ).toDF("account_number", "struct_data")

val schema = new StructType()
  .add($"key1".string)
  .add($"key2".string)
  .add($"keyn".string)

 val df2 = df.withColumn("st", from_json($"struct_data", schema))

 df2.printSchema
 df2.show(false)

这个 sn-p 导致这个输出:

root
 |-- account_number: integer (nullable = false)
 |-- struct_data: string (nullable = true)
 |-- st: struct (nullable = true)
 |    |-- key1: string (nullable = true)
 |    |-- key2: string (nullable = true)
 |    |-- keyn: string (nullable = true)

+--------------+---------------------------------------------------+------------------------+
|account_number|struct_data                                        |st                      |
+--------------+---------------------------------------------------+------------------------+
|123456789     |{"key1":"value","key2":"value2","keyn":"valuen"}   |[value,value2,valuen]   |
|987678909     |{"key1":"value0","key2":"value20","keyn":"valuen0"}|[value0,value20,valuen0]|
+--------------+---------------------------------------------------+------------------------+

【讨论】:

  • 我将其更改为 java 并获得了所需的输出。但是,当我运行它时,我得到了完全不同的错误。 java.lang.IllegalArgumentException: Illegal pattern component: XXX。浏览互联网后,我怀疑这是因为我有一些“YYYY-MM-DD”格式的日期数据。我被困住了。如何在模式中给出日期格式?如果可能,请为java spark 提供解决方案。 TIA。
  • 我相信最好将您的日期作为字符串拉入数据框中,然后使用 spark to_timestamp() 函数将它们转换,如下所述:stackoverflow.com/a/37449188/2639647
  • 请帮我解决这个问题。在您写的val df = Seq( (123456789, "{\"key1\":\"value\",\"key2\":\"value2\".... 的回答中,我无法读取这样的数据框,因为第二列包含许多这样的键值对。我想从 CSV 本身读取它。有可能吗?
  • 当然可以。只需改用Dataset&lt;Row&gt; df = spark.read().csv('/path/to/file')。然后,您的数据框应该为 CSV 中的每个字段都有一个字符串列。
  • 但是,如果我这样读,最后一列会因为里面的逗号而被打断。
猜你喜欢
  • 2015-11-11
  • 1970-01-01
  • 1970-01-01
  • 2020-07-12
  • 2016-01-03
  • 1970-01-01
  • 2017-10-31
  • 2018-04-26
  • 1970-01-01
相关资源
最近更新 更多